All of lore.kernel.org
 help / color / mirror / Atom feed
* [U-Boot] Read-only env variables
@ 2010-04-28  2:07 Joe Hershberger
  2010-05-06 21:58 ` Wolfgang Denk
  0 siblings, 1 reply; 124+ messages in thread
From: Joe Hershberger @ 2010-04-28  2:07 UTC (permalink / raw)
  To: u-boot

Hi u-boot,

I see u-boot supports readonly serial# and ethaddr, but I have a few
other variables that I need to be read-only.  I'm planning to
implement a generic list of variables that cannot be changed or
deleted.

I'm interested to know what sort of specification people would find
most appropriate.  My current thought is to follow the same delimiter
as the env itself, i.e. null separated list with double null
terminator.  This list would then be defined in the board config
header.  It also seems that you should be able to specify simple
access rules for each variable name perhaps using "=<val>" after each
var name where <val> could have constants (probably numbers for
performance, but could be string literals) to define modes.  Right now
I'm thinking read-only, create-only, change-default, and change-only
(i.e no delete) are the modes that make sense.

I'm also interested if anyone would be opposed to simply using this
new specification of readonly vars to implement the serial# and
ethaddr protection.  The CONFIG_HAS_UID is a bit odd... should that be
available in general for read-only vars?

Comments?

Thanks,
-Joe

^ permalink raw reply	[flat|nested] 124+ messages in thread

* [U-Boot] Read-only env variables
  2010-04-28  2:07 [U-Boot] Read-only env variables Joe Hershberger
@ 2010-05-06 21:58 ` Wolfgang Denk
  2010-05-10  6:30   ` Joe Hershberger
  0 siblings, 1 reply; 124+ messages in thread
From: Wolfgang Denk @ 2010-05-06 21:58 UTC (permalink / raw)
  To: u-boot

Dear Joe Hershberger,

In message <h2j4b538921004271907naebeb396t3928a9f41cc32046@mail.gmail.com> you wrote:
> 
> I see u-boot supports readonly serial# and ethaddr, but I have a few
> other variables that I need to be read-only.  I'm planning to
> implement a generic list of variables that cannot be changed or
> deleted.

Good idea, and thanks in advance!

> I'm interested to know what sort of specification people would find
> most appropriate.  My current thought is to follow the same delimiter
> as the env itself, i.e. null separated list with double null
> terminator.  This list would then be defined in the board config
> header.  It also seems that you should be able to specify simple
> access rules for each variable name perhaps using "=<val>" after each
> var name where <val> could have constants (probably numbers for
> performance, but could be string literals) to define modes.  Right now
> I'm thinking read-only, create-only, change-default, and change-only
> (i.e no delete) are the modes that make sense.

You might also go one step further and define variable types -
numeric, string, MAC addr, IP addr, ...

On the other hand I wonder if a compile-time defined, static list is
such a good idea. Why not putting this list in a variable itself? Then
users could use this feature to add their own r/o variables, or
protect already existing definitiins, etc. etc. [Note that you could
still prevent users from editing the list by including a reference to
itself.]

> I'm also interested if anyone would be opposed to simply using this
> new specification of readonly vars to implement the serial# and
> ethaddr protection.  The CONFIG_HAS_UID is a bit odd... should that be
> available in general for read-only vars?

If we had such a  feature, then all special handling of serial# and
ethaddr should go away, of course (this would also allow to fix the
inconsistent behaviour of ethaddr (read-only) versus eth<N>addr
(writable).

Regarding CONFIG_HAS_UID - I never understood what it was intended
for, and it is completely undocumented, and davinci_schmoogie and
MVSMR are the only boards that actually use it. It should be removed
from common code.

Sergey, Andre - comments?

Best regards,

Wolfgang Denk

-- 
DENX Software Engineering GmbH,     MD: Wolfgang Denk & Detlev Zundel
HRB 165235 Munich, Office: Kirchenstr.5, D-82194 Groebenzell, Germany
Phone: (+49)-8142-66989-10 Fax: (+49)-8142-66989-80 Email: wd at denx.de
You get a wonderful view from the point of no return.
                                    - Terry Pratchett, _Making_Money_

^ permalink raw reply	[flat|nested] 124+ messages in thread

* [U-Boot] Read-only env variables
  2010-05-06 21:58 ` Wolfgang Denk
@ 2010-05-10  6:30   ` Joe Hershberger
  2010-05-10  6:56     ` Wolfgang Denk
  0 siblings, 1 reply; 124+ messages in thread
From: Joe Hershberger @ 2010-05-10  6:30 UTC (permalink / raw)
  To: u-boot

On Thu, May 6, 2010 at 4:58 PM, Wolfgang Denk <wd@denx.de> wrote:

>
> You might also go one step further and define variable types -
> numeric, string, MAC addr, IP addr, ...
>
I'm guessing the reason for this being that the value can be validated on
set instead of on use?  I can see some interactive usability benefit to
this.  Also the Linux fw_setenv would be well served with this capability.


> On the other hand I wonder if a compile-time defined, static list is
> such a good idea. Why not putting this list in a variable itself? Then
> users could use this feature to add their own r/o variables, or
> protect already existing definitiins, etc. etc. [Note that you could
> still prevent users from editing the list by including a reference to
> itself.]


This is interesting.  I had considered this my self as an option for items
(such as ipaddr) which some times the user wants to change and save (static
ip) and other times would not like to save (ip set by dhcp).  This would
call for a dynamic configuration for the variables.  Having all of this in
an environment variable seems like it would get cumbersome to use rather
quickly.  I like the elegance of everything being in the env, but I'm not
sure that it's practical, especially if each variable name is assigned a
type and access control.

As I thought more about the implementation, I like the idea of using
bit-masks for each part of the access control that users can OR together in
their board config headers.  Unfortunately, that doesn't play nicely with
initializing default u-boot env variables due to the need to convert the
result of some expression into a string literal in the preprocessor.  I'm
not aware of any way to do that.  That also means that changing the
configuration in the env on the fly is tedious because the user must
remember the masks.  One way around this would be to make the default env
creation routing a bit more fancy and have it generate the env variable at
run-time based on the compiled in masks.

Another possibility that could make things simpler to use at runtime would
be to create a separate env variable for each access control bitmask element
and allow the user to simply add the variable names to those variables.
They get the behavior for each one the name is in.

Another thing that would make dealing with the lists in env variables easier
would be to support slightly different behavior for setenv...  here's what I
have in mind: if an env variable called "myList" contains
"varName1;varName2" and you call "setenv myList varName3", then the result
is myList contains "varName1;varName2;varName3".  If you then call "setenv
myList -varName2", then myList would contain "varName1;varName3".  The
behavior would be available in general by having a list variable type (just
like numeric or IP addr).  I'm not set on using semi-colons as list
delimiters or the "-" to signify remove-from-list in setenv, but those seem
natural.  I'm interested if there are any foreseeable issues with those
selections or if there are more appropriate options.


> If we had such a  feature, then all special handling of serial# and
> ethaddr should go away, of course (this would also allow to fix the
> inconsistent behaviour of ethaddr (read-only) versus eth<N>addr
> (writable).
>
I see we're on the same page about cleaning up these one-off behaviors.
Excellent.


> Regarding CONFIG_HAS_UID - I never understood what it was intended
> for, and it is completely undocumented, and davinci_schmoogie and
> MVSMR are the only boards that actually use it. It should be removed
> from common code.
>
I agree.  It really doesn't seem to fit, though it could be made one of the
access control types rather simply.

Best regards,
-Joe

^ permalink raw reply	[flat|nested] 124+ messages in thread

* [U-Boot] Read-only env variables
  2010-05-10  6:30   ` Joe Hershberger
@ 2010-05-10  6:56     ` Wolfgang Denk
  2010-05-10 19:16       ` Joe Hershberger
  0 siblings, 1 reply; 124+ messages in thread
From: Wolfgang Denk @ 2010-05-10  6:56 UTC (permalink / raw)
  To: u-boot

Dear Joe Hershberger,

In message <AANLkTil4TOC4Tmh0nZQXI8ahHT2LnwOmKLpsta_LFqrA@mail.gmail.com> you wrote:
>
> > You might also go one step further and define variable types -
> > numeric, string, MAC addr, IP addr, ...
> >
> I'm guessing the reason for this being that the value can be validated on
> set instead of on use?  I can see some interactive usability benefit to
> this.  Also the Linux fw_setenv would be well served with this capability.

Right, that was my intention.

> This is interesting.  I had considered this my self as an option for items
> (such as ipaddr) which some times the user wants to change and save (static
> ip) and other times would not like to save (ip set by dhcp).  This would
> call for a dynamic configuration for the variables.  Having all of this in
> an environment variable seems like it would get cumbersome to use rather
> quickly.  I like the elegance of everything being in the env, but I'm not
> sure that it's practical, especially if each variable name is assigned a
> type and access control.

Well, we could go for a simple type scheme, something like

	d - decimal number
	i - IP address
	m - mac address
	s - string
	x - hex number
	...

plus similarly simple access control codes:

	d - no change except reset to default possible
	o - one-time setting, no changes afterward
	r - read-only
	(none) - unrestricted access

Then we could do something like:

setenv acl delay:d,address:a,ipaddr:i,ethaddr:mo,serial#:sr

The only disadvantage is that the meaning of the qualifiers is
position dependent, but I think this is acceptable for the purposes we
have in mind.

> As I thought more about the implementation, I like the idea of using
> bit-masks for each part of the access control that users can OR together in
> their board config headers.  Unfortunately, that doesn't play nicely with
> initializing default u-boot env variables due to the need to convert the
> result of some expression into a string literal in the preprocessor.  I'm
> not aware of any way to do that.  That also means that changing the
> configuration in the env on the fly is tedious because the user must
> remember the masks.  One way around this would be to make the default env
> creation routing a bit more fancy and have it generate the env variable at
> run-time based on the compiled in masks.

I think bitmasks is probably overkill - we probably don't need that
many options. The scheme above could be extended for more qualifiers
as well.

> Another thing that would make dealing with the lists in env variables easier
> would be to support slightly different behavior for setenv...  here's what I
> have in mind: if an env variable called "myList" contains
> "varName1;varName2" and you call "setenv myList varName3", then the result
> is myList contains "varName1;varName2;varName3".  If you then call "setenv

That would be incompatible to existing use. Not a good idea, IMHO.

> myList -varName2", then myList would contain "varName1;varName3".  The
> behavior would be available in general by having a list variable type (just
> like numeric or IP addr).  I'm not set on using semi-colons as list
> delimiters or the "-" to signify remove-from-list in setenv, but those seem
> natural.  I'm interested if there are any foreseeable issues with those
> selections or if there are more appropriate options.

What would be your use of such list vatiables?

And what's wrong with 

	setenv myList "varName1;varName2"
	setenv myList "$myList;varName3"

to do the same as above, using only the existing feature set?

OK, the "remove entry" function is not that easy here, but which usage
do you have in mind that needs that?  I never ran into that before.

> --0016e640d1748106790486378cdb
> Content-Type: text/html; charset=ISO-8859-1
> Content-Transfer-Encoding: quoted-printable

Please stop this.

Best regards,

Wolfgang Denk

-- 
DENX Software Engineering GmbH,     MD: Wolfgang Denk & Detlev Zundel
HRB 165235 Munich, Office: Kirchenstr.5, D-82194 Groebenzell, Germany
Phone: (+49)-8142-66989-10 Fax: (+49)-8142-66989-80 Email: wd at denx.de
If something is different, it's either better or worse,  and  usually
both.                                                    - Larry Wall

^ permalink raw reply	[flat|nested] 124+ messages in thread

* [U-Boot] Read-only env variables
  2010-05-10  6:56     ` Wolfgang Denk
@ 2010-05-10 19:16       ` Joe Hershberger
  2010-05-10 20:43         ` Wolfgang Denk
  0 siblings, 1 reply; 124+ messages in thread
From: Joe Hershberger @ 2010-05-10 19:16 UTC (permalink / raw)
  To: u-boot

On Mon, May 10, 2010 at 1:56 AM, Wolfgang Denk <wd@denx.de> wrote:
> Well, we could go for a simple type scheme, something like
>
> ? ? ? ?d - decimal number
> ? ? ? ?i - IP address
> ? ? ? ?m - mac address
> ? ? ? ?s - string
> ? ? ? ?x - hex number
> ? ? ? ?...

       l - list delimited by ';' (special behavior for setenv)

> plus similarly simple access control codes:
>
> ? ? ? ?d - no change except reset to default possible
> ? ? ? ?o - one-time setting, no changes afterward
> ? ? ? ?r - read-only
> ? ? ? ?(none) - unrestricted access
>
> Then we could do something like:
>
> setenv acl delay:d,address:a,ipaddr:i,ethaddr:mo,serial#:sr
>
> The only disadvantage is that the meaning of the qualifiers is
> position dependent, but I think this is acceptable for the purposes we
> have in mind.

That seems pretty reasonable.  I think I'd like to see the access
control codes more role based than limitation based.  Such as:

     u - unique board configuration (mac addr, ser#)... set if not
set, default override
     s - script in env var... read only, default
     r - runtime variable (ip addr)... set in env, not saveable to flash.

> I think bitmasks is probably overkill - we probably don't need that
> many options. The scheme above could be extended for more qualifiers
> as well.

I think I will at least use bitmasks to define each of the commands
that are available in the acl env var.  That will make defining new
commands simple.

>> Another thing that would make dealing with the lists in env variables easier
>> would be to support slightly different behavior for setenv... ?here's what I
>> have in mind: if an env variable called "myList" contains
>> "varName1;varName2" and you call "setenv myList varName3", then the result
>> is myList contains "varName1;varName2;varName3". ?If you then call "setenv
>
> That would be incompatible to existing use. Not a good idea, IMHO.
>
>> myList -varName2", then myList would contain "varName1;varName3". ?The
>> behavior would be available in general by having a list variable type (just
>> like numeric or IP addr). ?I'm not set on using semi-colons as list
>> delimiters or the "-" to signify remove-from-list in setenv, but those seem
>> natural. ?I'm interested if there are any foreseeable issues with those
>> selections or if there are more appropriate options.
>
> What would be your use of such list vatiables?

Specifically for manipulating the acl and any other list that a user
may need.  Because it will self reference and define its type as a
list,

> And what's wrong with
>
> ? ? ? ?setenv myList "varName1;varName2"
> ? ? ? ?setenv myList "$myList;varName3"
>
> to do the same as above, using only the existing feature set?

There's nothing wrong with that, but the issue is with removal... and
if you are making the behavior special for lists, then this is cleaner
than dereferencing the original list every time.

> OK, the "remove entry" function is not that easy here, but which usage
> do you have in mind that needs that? ?I never ran into that before.

Consider the case where a variable is defined as a runtime variable,
but the user would like to change the value and commit that change to
flash.  It would be much more usable if there were a simple way to
remove an element from a list.

>> --0016e640d1748106790486378cdb
>> Content-Type: text/html; charset=ISO-8859-1
>> Content-Transfer-Encoding: quoted-printable
>
> Please stop this.

Apologies.

Best regards,
-Joe

^ permalink raw reply	[flat|nested] 124+ messages in thread

* [U-Boot] Read-only env variables
  2010-05-10 19:16       ` Joe Hershberger
@ 2010-05-10 20:43         ` Wolfgang Denk
  2010-05-10 21:33           ` Joe Hershberger
  0 siblings, 1 reply; 124+ messages in thread
From: Wolfgang Denk @ 2010-05-10 20:43 UTC (permalink / raw)
  To: u-boot

Dear Joe Hershberger,

In message <AANLkTimqkxOkQeNTy8OcYqNVxNK5rLMoqHoRSnFqQnqk@mail.gmail.com> you wrote:
> On Mon, May 10, 2010 at 1:56 AM, Wolfgang Denk <wd@denx.de> wrote:
> > Well, we could go for a simple type scheme, something like
> >
> >        d - decimal number
> >        i - IP address
> >        m - mac address
> >        s - string
> >        x - hex number
> >        ...
>
>        l - list delimited by ';' (special behavior for setenv)

Don't do this. ';' has a clear meaning. Using it for other purposes

> That seems pretty reasonable.  I think I'd like to see the access
> control codes more role based than limitation based.  Such as:
>
>      u - unique board configuration (mac addr, ser#)... set if not
> set, default override
>      s - script in env var... read only, default
>      r - runtime variable (ip addr)... set in env, not saveable to flash.

This is most probably less flexible and more cumbersome to use.  It's
easier  to  define  what  exactly  you  want to do (don't allow over-
writing) that finding a role that happens to include this  behaviour.
Think  also  about  the  end  user  who wonders why variable "foo" is
considered to be a "unique board configuration" when all  you  wanted
is to apply certain behaviour.

> > What would be your use of such list vatiables?
>
> Specifically for manipulating the acl and any other list that a user
> may need.  Because it will self reference and define its type as a
> list,

Why would that be needed?

See my example above:

	setenv acl delay:d,address:a,ipaddr:i,ethaddr:mo,serial#:sr

[Implementation note: the implementation should allow for and ignore
repeated or trailing ',' separators - i.e. something like
"delay:d,,,address:a,ipaddr:i,ethaddr:mo,,serial#:sr,," should work
as well. Reason: see below about incremental building.]

> There's nothing wrong with that, but the issue is with removal... and
> if you are making the behavior special for lists, then this is cleaner
> than dereferencing the original list every time.

Well, we have the editenv command, which makes editing pretty easy.
I fear/feal that adding lists is (1) not really needed and thus most
likely more overhead than benefit, and (2) holds a lot of potential
for causing confusion and conflicts.

We don't have lists vailables in bash either (or do we?)

> > OK, the "remove entry" function is not that easy here, but which usage
> > do you have in mind that needs that?  I never ran into that before.
>
> Consider the case where a variable is defined as a runtime variable,
> but the user would like to change the value and commit that change to
> flash.  It would be much more usable if there were a simple way to
> remove an element from a list.

What to you mean by "runtime variable" or by "change to flash"? I
don;t understand what these terms are supposed to mean.  As mentioned
before, "editenv" seems a pretty straightforward way to edit the
settings.

I feel we should try to make this not overly complicated - don't add
bells and whistles without real need. Also keep in mind that a lot of
power results from being able to dynamically build such settings from
smaller blocks.

I can imagine scripts that run things like

	setenv acl "$acl_net,$acl_hw_id,$acl_foo,$acl_bar"

Best regards,

Wolfgang Denk

-- 
DENX Software Engineering GmbH,     MD: Wolfgang Denk & Detlev Zundel
HRB 165235 Munich, Office: Kirchenstr.5, D-82194 Groebenzell, Germany
Phone: (+49)-8142-66989-10 Fax: (+49)-8142-66989-80 Email: wd at denx.de
That's the thing about people who think  they  hate  computers.  What
they really hate is lousy programmers.
- Larry Niven and Jerry Pournelle in "Oath of Fealty"

^ permalink raw reply	[flat|nested] 124+ messages in thread

* [U-Boot] Read-only env variables
  2010-05-10 20:43         ` Wolfgang Denk
@ 2010-05-10 21:33           ` Joe Hershberger
  2010-05-11 20:19             ` Craig Millen
  0 siblings, 1 reply; 124+ messages in thread
From: Joe Hershberger @ 2010-05-10 21:33 UTC (permalink / raw)
  To: u-boot

On Mon, May 10, 2010 at 3:43 PM, Wolfgang Denk <wd@denx.de> wrote:
>> ? ? ? ?l - list delimited by ';' (special behavior for setenv)
>
> Don't do this. ';' has a clear meaning. Using it for other purposes

Fair enough... ',' then.

>> That seems pretty reasonable. ?I think I'd like to see the access
>> control codes more role based than limitation based. ?Such as:
>>
>> ? ? ?u - unique board configuration (mac addr, ser#)... set if not
>> set, default override
>> ? ? ?s - script in env var... read only, default
>> ? ? ?r - runtime variable (ip addr)... set in env, not saveable to flash.
>
> This is most probably less flexible and more cumbersome to use. ?It's
> easier ?to ?define ?what ?exactly ?you ?want to do (don't allow over-
> writing) that finding a role that happens to include this ?behaviour.
> Think ?also ?about ?the ?end ?user ?who wonders why variable "foo" is
> considered to be a "unique board configuration" when all ?you ?wanted
> is to apply certain behaviour.

The primary reason for wanting this sort of comes back to the reason I
wanted bitmasks in the first place.  I want to be able to mix certain
access control attributes for different variables.

I've added a command called "defaultenv" which comes in really handy
in practice here.  Basically what it does is revert everything in
memory to a default env except for certain (currently hard coded)
variables such as ethaddr and serial#.  This means that if I rebuild
and change a script or boot command, my people can simply load the new
u-boot and run "defaultenv;saveenv" to get the updated scripts but not
have to redefine all the board unique variables like they would if
they just erased their env sectors.  I'd like to specify that a
variable should be preserved on reverting to default env independent
of being read-only or not.  Perhaps you would prefer to have each
permutation defined as a sum of attributes instead of a role.  It's
the same thing with a different name.

>> > What would be your use of such list vatiables?
>>
>> Specifically for manipulating the acl and any other list that a user
>> may need. ?Because it will self reference and define its type as a
>> list,
>
> Why would that be needed?
>
> See my example above:
>
> ? ? ? ?setenv acl delay:d,address:a,ipaddr:i,ethaddr:mo,serial#:sr

The idea was that if you wanted to remove "ethaddr:mo" from the list
for instance, you could do so without dealing with the rest of the
items in the list.  See below.

> [Implementation note: the implementation should allow for and ignore
> repeated or trailing ',' separators - i.e. something like
> "delay:d,,,address:a,ipaddr:i,ethaddr:mo,,serial#:sr,," should work
> as well. Reason: see below about incremental building.]

I agree.  It will be tolerant of this.

> Well, we have the editenv command, which makes editing pretty easy.
> I fear/feal that adding lists is (1) not really needed and thus most
> likely more overhead than benefit, and (2) holds a lot of potential
> for causing confusion and conflicts.

I haven't used the editenv command, so I'll play with that a bit.  It
sounds like it will make my concern about removal less of an issue.
I'll try it and see how usability feels.

> We don't have lists vailables in bash either (or do we?)

Not that I'm aware of.  Arrays, yes, but that's not what I'm going for here.

>> > OK, the "remove entry" function is not that easy here, but which usage
>> > do you have in mind that needs that? ?I never ran into that before.
>>
>> Consider the case where a variable is defined as a runtime variable,
>> but the user would like to change the value and commit that change to
>> flash. ?It would be much more usable if there were a simple way to
>> remove an element from a list.
>
> What to you mean by "runtime variable" or by "change to flash"? I
> don;t understand what these terms are supposed to mean. ?As mentioned
> before, "editenv" seems a pretty straightforward way to edit the
> settings.

What I'm referring to here is being able to specify a variable as r/w
while running in u-boot, but that that value will not be written to
flash.  If the value was defined in flash, then the existing value in
flash will be retained when saveenv is called.  Again, I'm considering
the case with "ipaddr" and family.  If the user wishes to change the
static IP, then that change should be written to flash.  If the user
wishes to use dhcp to configure all the network settings, those
settings should not be saved to flash (and then used as though they
were static settings).  Currently if you use dhcp and then want to
save some other change in the env, you save all the dhcp settings and
the next time the board is powered, you use an address that you have
no lease for and probably conflict with another machine.

> I feel we should try to make this not overly complicated - don't add
> bells and whistles without real need. Also keep in mind that a lot of
> power results from being able to dynamically build such settings from
> smaller blocks.

I also don't want it to be complicated, but I'd like it to cover the
use cases that I'm up against at the moment in a relatively user
friendly way.  I feel like we are close to a solution.

> I can imagine scripts that run things like
>
> ? ? ? ?setenv acl "$acl_net,$acl_hw_id,$acl_foo,$acl_bar"

That sounds great.  I also envision making part of the acl
unchangeable and part of it changeable.  That would be done by making
the the acl reference itself as read-only and also contain a
dereference such as:
"acl=$acl_rw,acl:sr,ipaddr:i,ethaddr:mo,serial#:sr".  You could then
change the value of acl_rw at runtime but not the value of acl.

One thing I've noticed that I don't quite understand is how you can
add a '$' to a variable's value from the command line.  If I escape it
with a '\', the '\' sticks around in the value of the variable, but if
I don't escape it, then the '$' dereferences in the setenv.  Seems
like a bug to me.  The '\' should not end up in the value of the var
when used in setenv to escape the '$'.

Best regards,
-Joe

^ permalink raw reply	[flat|nested] 124+ messages in thread

* [U-Boot] Read-only env variables
  2010-05-10 21:33           ` Joe Hershberger
@ 2010-05-11 20:19             ` Craig Millen
  2010-05-11 22:03               ` Wolfgang Denk
  0 siblings, 1 reply; 124+ messages in thread
From: Craig Millen @ 2010-05-11 20:19 UTC (permalink / raw)
  To: u-boot

I ran into the same situation, where I needed set of environment variables for in house testing, and a different set for when products actually go out to customers. So we were erasing the flash quite often, but in this scenario, things like serial number and mac address stay with the board regardless if we replace all of the memory on the board. 
I wrote a mirror image of the environment variable handling routines, but used a small serial EEPROM that could hold a 100 bytes. 

We modified the fw_env to parse the serial EEPROM as well. 

So everything that is in the serial EEPROM is accessed by a mirrored set of commands like "protected_saveenv" and "protected_printenv" that are hidden from the user in the help. 

I integrated the "protected environment" into the regular environment by looking through the protected space first before allowing any "setenv" and when a "printenv" is done, it will print the protected variables last.

Unfortunately our u-boot is heavily modified in or to make it production worthy, so we've never been able to enter it into the repository.  I can however provide you will all the code necessary if you would like. 


-----Original Message-----
From: u-boot-bounces@lists.denx.de [mailto:u-boot-bounces at lists.denx.de] On Behalf Of Joe Hershberger
Sent: Monday, May 10, 2010 5:34 PM
To: Wolfgang Denk
Cc: u-boot
Subject: Re: [U-Boot] Read-only env variables

On Mon, May 10, 2010 at 3:43 PM, Wolfgang Denk <wd@denx.de> wrote:
>> ? ? ? ?l - list delimited by ';' (special behavior for setenv)
>
> Don't do this. ';' has a clear meaning. Using it for other purposes

Fair enough... ',' then.

>> That seems pretty reasonable. ?I think I'd like to see the access 
>> control codes more role based than limitation based. ?Such as:
>>
>> ? ? ?u - unique board configuration (mac addr, ser#)... set if not 
>> set, default override
>> ? ? ?s - script in env var... read only, default
>> ? ? ?r - runtime variable (ip addr)... set in env, not saveable to flash.
>
> This is most probably less flexible and more cumbersome to use. ?It's 
> easier ?to ?define ?what ?exactly ?you ?want to do (don't allow over-
> writing) that finding a role that happens to include this ?behaviour.
> Think ?also ?about ?the ?end ?user ?who wonders why variable "foo" is 
> considered to be a "unique board configuration" when all ?you ?wanted 
> is to apply certain behaviour.

The primary reason for wanting this sort of comes back to the reason I wanted bitmasks in the first place.  I want to be able to mix certain access control attributes for different variables.

I've added a command called "defaultenv" which comes in really handy in practice here.  Basically what it does is revert everything in memory to a default env except for certain (currently hard coded) variables such as ethaddr and serial#.  This means that if I rebuild and change a script or boot command, my people can simply load the new u-boot and run "defaultenv;saveenv" to get the updated scripts but not have to redefine all the board unique variables like they would if they just erased their env sectors.  I'd like to specify that a variable should be preserved on reverting to default env independent of being read-only or not.  Perhaps you would prefer to have each permutation defined as a sum of attributes instead of a role.  It's the same thing with a different name.

>> > What would be your use of such list vatiables?
>>
>> Specifically for manipulating the acl and any other list that a user 
>> may need. ?Because it will self reference and define its type as a 
>> list,
>
> Why would that be needed?
>
> See my example above:
>
> ? ? ? ?setenv acl delay:d,address:a,ipaddr:i,ethaddr:mo,serial#:sr

The idea was that if you wanted to remove "ethaddr:mo" from the list for instance, you could do so without dealing with the rest of the items in the list.  See below.

> [Implementation note: the implementation should allow for and ignore 
> repeated or trailing ',' separators - i.e. something like 
> "delay:d,,,address:a,ipaddr:i,ethaddr:mo,,serial#:sr,," should work as 
> well. Reason: see below about incremental building.]

I agree.  It will be tolerant of this.

> Well, we have the editenv command, which makes editing pretty easy.
> I fear/feal that adding lists is (1) not really needed and thus most 
> likely more overhead than benefit, and (2) holds a lot of potential 
> for causing confusion and conflicts.

I haven't used the editenv command, so I'll play with that a bit.  It sounds like it will make my concern about removal less of an issue.
I'll try it and see how usability feels.

> We don't have lists vailables in bash either (or do we?)

Not that I'm aware of.  Arrays, yes, but that's not what I'm going for here.

>> > OK, the "remove entry" function is not that easy here, but which 
>> > usage do you have in mind that needs that? ?I never ran into that before.
>>
>> Consider the case where a variable is defined as a runtime variable, 
>> but the user would like to change the value and commit that change to 
>> flash. ?It would be much more usable if there were a simple way to 
>> remove an element from a list.
>
> What to you mean by "runtime variable" or by "change to flash"? I 
> don;t understand what these terms are supposed to mean. ?As mentioned 
> before, "editenv" seems a pretty straightforward way to edit the 
> settings.

What I'm referring to here is being able to specify a variable as r/w while running in u-boot, but that that value will not be written to flash.  If the value was defined in flash, then the existing value in flash will be retained when saveenv is called.  Again, I'm considering the case with "ipaddr" and family.  If the user wishes to change the static IP, then that change should be written to flash.  If the user wishes to use dhcp to configure all the network settings, those settings should not be saved to flash (and then used as though they were static settings).  Currently if you use dhcp and then want to save some other change in the env, you save all the dhcp settings and the next time the board is powered, you use an address that you have no lease for and probably conflict with another machine.

> I feel we should try to make this not overly complicated - don't add 
> bells and whistles without real need. Also keep in mind that a lot of 
> power results from being able to dynamically build such settings from 
> smaller blocks.

I also don't want it to be complicated, but I'd like it to cover the use cases that I'm up against at the moment in a relatively user friendly way.  I feel like we are close to a solution.

> I can imagine scripts that run things like
>
> ? ? ? ?setenv acl "$acl_net,$acl_hw_id,$acl_foo,$acl_bar"

That sounds great.  I also envision making part of the acl unchangeable and part of it changeable.  That would be done by making the the acl reference itself as read-only and also contain a dereference such as:
"acl=$acl_rw,acl:sr,ipaddr:i,ethaddr:mo,serial#:sr".  You could then change the value of acl_rw at runtime but not the value of acl.

One thing I've noticed that I don't quite understand is how you can add a '$' to a variable's value from the command line.  If I escape it with a '\', the '\' sticks around in the value of the variable, but if I don't escape it, then the '$' dereferences in the setenv.  Seems like a bug to me.  The '\' should not end up in the value of the var when used in setenv to escape the '$'.

Best regards,
-Joe
_______________________________________________
U-Boot mailing list
U-Boot at lists.denx.de
http://lists.denx.de/mailman/listinfo/u-boot

^ permalink raw reply	[flat|nested] 124+ messages in thread

* [U-Boot] Read-only env variables
  2010-05-11 20:19             ` Craig Millen
@ 2010-05-11 22:03               ` Wolfgang Denk
  2010-05-11 22:52                 ` Joe Hershberger
  0 siblings, 1 reply; 124+ messages in thread
From: Wolfgang Denk @ 2010-05-11 22:03 UTC (permalink / raw)
  To: u-boot

Dear "Craig Millen",

In message <67BFAF42E016FC40ADE4EE73E07B706004668DD0@pks00005.kanatek.com> you wrote:
> I ran into the same situation, where I needed set of environment
> variables for in house testing, and a different set for when products
> actually go out to customers. So we were erasing the flash quite often,
> but in this scenario, things like serial number and mac address stay
> with the board regardless if we replace all of the memory on the board. 
> I wrote a mirror image of the environment variable handling routines,
> but used a small serial EEPROM that could hold a 100 bytes. 

There are other boards doing similar things - see for example
board/tqc/tqm8xx/load_sernum_ethaddr.c which can pre-load the MAC
address and serial number on all TQM8xxL/TQM8xxM/TQM82xx boards from a
dedicated area in flash.

> I've added a command called "defaultenv" which comes in really handy in
> practice here.  Basically what it does is revert everything in memory to
> a default env except for certain (currently hard coded) variables such
> as ethaddr and serial#.  This means that if I rebuild and change a
> script or boot command, my people can simply load the new u-boot and run
> "defaultenv;saveenv" to get the updated scripts but not have to redefine

There has been discussion about such a feature in the past. I even
tried to define the user interface for such a command set, but
unfortunately I didn't have enough time myself and nobody else took
the bait either.

> I haven't used the editenv command, so I'll play with that a bit.  It
> sounds like it will make my concern about removal less of an issue.
> I'll try it and see how usability feels.

Yes, it will make it less an issue - as far as interactive use is
concerned. But then I still see why you want such a feature fr example
for use in scripts.

We agree that the feature is useful, but I am not convinced that the
list approach makes sense. Eventually I'd rather have a scriptable
edit command. IIRC there was a vi clone in one of the IOCCC
submissions with < 1.5k code... :-)

> > What to you mean by "runtime variable" or by "change to flash"? I 
> > don;t understand what these terms are supposed to mean. ?As
> mentioned 
> > before, "editenv" seems a pretty straightforward way to edit the 
> > settings.
> 
> What I'm referring to here is being able to specify a variable as r/w
> while running in u-boot, but that that value will not be written to
> flash.  If the value was defined in flash, then the existing value in

Ah. But you have this already, when using the hush shell. It has shell
variables (which work exactly like your r/w variables), and you have
environment variables.

All you eventually need is a script / macro to initialize the shell
variables after boot.

> the case with "ipaddr" and family.  If the user wishes to change the
> static IP, then that change should be written to flash.  If the user
> wishes to use dhcp to configure all the network settings, those settings
> should not be saved to flash (and then used as though they were static

Be careful. You are defining policy here, and actually you can do all
this already now.

Use "setenv ipaddr ...; saveenv" if the user wishes to change the
static IP and write it to flash.

Use "dhcp" (without "saveenv") to use dhcp to configure all the
network settings without saving this to flash.

What else do you need?

> settings).  Currently if you use dhcp and then want to save some other
> change in the env, you save all the dhcp settings and the next time the
> board is powered, you use an address that you have no lease for and
> probably conflict with another machine.

Well, then just do the saveenv _before_ you use DHCP. Or be careful
to delete / reset the respective variables.

I agree, your vision is to make this easier, but in this specific case
I doubt the benefits justify the additional overhead.


> One thing I've noticed that I don't quite understand is how you can add
> a '$' to a variable's value from the command line.  If I escape it with
> a '\', the '\' sticks around in the value of the variable, but if I
> don't escape it, then the '$' dereferences in the setenv.  Seems like a
> bug to me.  The '\' should not end up in the value of the var when used
> in setenv to escape the '$'.

I can't parse that. Do you have an example?

Best regards,

Wolfgang Denk

-- 
DENX Software Engineering GmbH,     MD: Wolfgang Denk & Detlev Zundel
HRB 165235 Munich, Office: Kirchenstr.5, D-82194 Groebenzell, Germany
Phone: (+49)-8142-66989-10 Fax: (+49)-8142-66989-80 Email: wd at denx.de
The only way to get rid of a temptation is to yield to it.
                                                        - Oscar Wilde

^ permalink raw reply	[flat|nested] 124+ messages in thread

* [U-Boot] Read-only env variables
  2010-05-11 22:03               ` Wolfgang Denk
@ 2010-05-11 22:52                 ` Joe Hershberger
  2010-05-12  9:34                   ` Wolfgang Denk
  0 siblings, 1 reply; 124+ messages in thread
From: Joe Hershberger @ 2010-05-11 22:52 UTC (permalink / raw)
  To: u-boot

On Tue, May 11, 2010 at 5:03 PM, Wolfgang Denk <wd@denx.de> wrote:
> In message <67BFAF42E016FC40ADE4EE73E07B706004668DD0@pks00005.kanatek.com> you wrote:
>> I ran into the same situation, where I needed set of environment
>> variables for in house testing, and a different set for when products
>> actually go out to customers. So we were erasing the flash quite often,
>> but in this scenario, things like serial number and mac address stay
>> with the board regardless if we replace all of the memory on the board.
>> I wrote a mirror image of the environment variable handling routines,
>> but used a small serial EEPROM that could hold a 100 bytes.

I don't have a separate memory to use for this purpose, but it seems
like a good approach if you do.

> There has been discussion about such a feature in the past. I even
> tried to define the user interface for such a command set, but
> unfortunately I didn't have enough time myself and nobody else took
> the bait either.

Ok... if you can dig up the user interface you were thinking of, I can
compare it to what I've done and possibly tweak it.  As it is now, I
intend to use the acl to define which variables are preserved.  The
command takes no arguments and changes only the in-RAM environment.

>> I haven't used the editenv command, so I'll play with that a bit. ?It
>> sounds like it will make my concern about removal less of an issue.
>> I'll try it and see how usability feels.
>
> Yes, it will make it less an issue - as far as interactive use is
> concerned. But then I still see why you want such a feature fr example
> for use in scripts.

Both in scripts and when called directly from other commands.

> We agree that the feature is useful, but I am not convinced that the
> list approach makes sense. Eventually I'd rather have a scriptable
> edit command. IIRC there was a vi clone in one of the IOCCC
> submissions with < 1.5k code... :-)

:)  I was going for simple(r).

> Ah. But you have this already, when using the hush shell. It has shell
> variables (which work exactly like your r/w variables), and you have
> environment variables.
>
> All you eventually need is a script / macro to initialize the shell
> variables after boot.

I'll have to look into this.  I've noticed their existence, but
haven't used them so far.  I can see how that would help for
intermediate state storage (as long as they stay around through every
context such as from preboot to bootcmd), but not for variables that
need to be accessible to u-boot (such as network settings).

>> the case with "ipaddr" and family. ?If the user wishes to change the
>> static IP, then that change should be written to flash. ?If the user
>> wishes to use dhcp to configure all the network settings, those settings
>> should not be saved to flash (and then used as though they were static
>
> Be careful. You are defining policy here, and actually you can do all
> this already now.

I want the acl to be the one defining this policy.

> Use "setenv ipaddr ...; saveenv" if the user wishes to change the
> static IP and write it to flash.

Works great in a vacuum.

> Use "dhcp" (without "saveenv") to use dhcp to configure all the
> network settings without saving this to flash.

In the case of dhcp, the key is that I want to be able to save some
unrelated change to the environment... I shouldn't be prevented from
doing it because I happened to configure the network already.

>> settings). ?Currently if you use dhcp and then want to save some other
>> change in the env, you save all the dhcp settings and the next time the
>> board is powered, you use an address that you have no lease for and
>> probably conflict with another machine.
>
> Well, then just do the saveenv _before_ you use DHCP. Or be careful

Not possible for the use case... I'm using netconsole, so dhcp must be
first to make the console accessible... so no change made to the env
could ever be saved.

> to delete / reset the respective variables.

That's tedious.  I think it should be better.  Making it better is
part of the reason for doing this.

> I agree, your vision is to make this easier, but in this specific case
> I doubt the benefits justify the additional overhead.

All of this stems from the fact that a number of env vars are magical.
 Things like "ipaddr" and "stdin" etc. are hooked up to internals of
u-boot.  In the case of stdin and family, the behavior (without
CONFIG_SYS_CONSOLE_IS_IN_ENV) is that those variables only affect the
run-time behavior and are not written to flash.  I'm certain that the
reason for that is the same as the issue I'm having with the network
configuration.  I think there should be a simple-to-use way to
indicate that a magical env var should be only magical and not in
flash or possibly initialized from flash but not saved.  Since I'm
making an ACL, it seemed reasonable to implement that behavior
generically.  The list behavior idea was an attempt at making the acl
easier to change, since it would need to be changed (by users,
scripts, and u-boot code) for several different use cases.

>> One thing I've noticed that I don't quite understand is how you can add
>> a '$' to a variable's value from the command line. ?If I escape it with
>> a '\', the '\' sticks around in the value of the variable, but if I
>> don't escape it, then the '$' dereferences in the setenv. ?Seems like a
>> bug to me. ?The '\' should not end up in the value of the var when used
>> in setenv to escape the '$'.
>
> I can't parse that. Do you have an example?

Run this command:

setenv a "\$x";printenv a;setenv b "$x";printenv b

Neither one ends up containing "$x".  I believe that the first one should.

Best regards,
-Joe

^ permalink raw reply	[flat|nested] 124+ messages in thread

* [U-Boot] Read-only env variables
  2010-05-11 22:52                 ` Joe Hershberger
@ 2010-05-12  9:34                   ` Wolfgang Denk
  2010-05-12 23:46                     ` Joe Hershberger
  0 siblings, 1 reply; 124+ messages in thread
From: Wolfgang Denk @ 2010-05-12  9:34 UTC (permalink / raw)
  To: u-boot

Dear Joe Hershberger,

In message <AANLkTil26wmjRI5oq2iMFnNEc8LGoYlSjbGoQKTLxLbw@mail.gmail.com> you wrote:
>
> >> I ran into the same situation, where I needed set of environment
> >> variables for in house testing, and a different set for when products
> >> actually go out to customers. So we were erasing the flash quite often,
> >> but in this scenario, things like serial number and mac address stay
> >> with the board regardless if we replace all of the memory on the board.
> >> I wrote a mirror image of the environment variable handling routines,
> >> but used a small serial EEPROM that could hold a 100 bytes.
> 
> I don't have a separate memory to use for this purpose, but it seems
> like a good approach if you do.

In most cases the compiled-in default environment should be sufficient
for this purpose.

> > There has been discussion about such a feature in the past. I even
> > tried to define the user interface for such a command set, but
> > unfortunately I didn't have enough time myself and nobody else took
> > the bait either.
> 
> Ok... if you can dig up the user interface you were thinking of, I can
> compare it to what I've done and possibly tweak it.  As it is now, I
> intend to use the acl to define which variables are preserved.  The
> command takes no arguments and changes only the in-RAM environment.

See here:

http://thread.gmane.org/gmane.comp.boot-loaders.u-boot/36570/focus=36861

Taking this one step further, we should then also rename "editenv"
into "env edit".

Re-reading the proposal, I still like the suggested user interface.


> I'll have to look into this.  I've noticed their existence, but
> haven't used them so far.  I can see how that would help for
> intermediate state storage (as long as they stay around through every
> context such as from preboot to bootcmd), but not for variables that
> need to be accessible to u-boot (such as network settings).

You can of course initialize environment variables from values stored
in shell variables, i. e.

	setenv ipaddr ${var}

> >> the case with "ipaddr" and family.  If the user wishes to change the
> >> static IP, then that change should be written to flash.  If the user
> >> wishes to use dhcp to configure all the network settings, those settings
> >> should not be saved to flash (and then used as though they were static
> >
> > Be careful. You are defining policy here, and actually you can do all
> > this already now.
> 
> I want the acl to be the one defining this policy.

But this is IMHO wrong. The ACl should describe properties, i. e. if a
variable can be written or not etc.  It should NEVER try to define how
the user deploys the properties of a variable.

> > Use "setenv ipaddr ...; saveenv" if the user wishes to change the
> > static IP and write it to flash.
> 
> Works great in a vacuum.

? What do you mean here?

> > Use "dhcp" (without "saveenv") to use dhcp to configure all the
> > network settings without saving this to flash.
> 
> In the case of dhcp, the key is that I want to be able to save some
> unrelated change to the environment... I shouldn't be prevented from
> doing it because I happened to configure the network already.

I don't see your problem. If you want to define a default IP address
and want to use this as "ipaddr" environment variable unless DHCP
overwrites this value, then you can easily do that:

	=> setenv default_ipaddr aa.bb.cc.dd
	=> setenv default_netmask ...
	...
	=> setenv net_default 'setenv ipaddr ${default_ipaddr};setenv netmask ${default_netmask};...'
	=> setenv preboot run net_default


How would you in your szenario, where "dhcp" can change the "ipaddr"
environment variable, but a saveenv would not save it, set a new
"ipaddr"?

Me thinks you are adding complexity here without need, plus potential
for lots of confusion.


> > Well, then just do the saveenv _before_ you use DHCP. Or be careful
> 
> Not possible for the use case... I'm using netconsole, so dhcp must be
> first to make the console accessible... so no change made to the env
> could ever be saved.

OK, then do as described above and consider the variables set by DHCP
as volatile and do not attempt to use these to store your default
settings that are supposed to be persistent.

> All of this stems from the fact that a number of env vars are magical.
>  Things like "ipaddr" and "stdin" etc. are hooked up to internals of
> u-boot.  In the case of stdin and family, the behavior (without
> CONFIG_SYS_CONSOLE_IS_IN_ENV) is that those variables only affect the
> run-time behavior and are not written to flash.  I'm certain that the
> reason for that is the same as the issue I'm having with the network

No, the reason is more likely that the one who implemented this did
just what he actually needed, without a clear concept for such a
global scope. The next one who needed different behaviour added
CONFIG_SYS_CONSOLE_IS_IN_ENV. Now we have both.

> configuration.  I think there should be a simple-to-use way to
> indicate that a magical env var should be only magical and not in
> flash or possibly initialized from flash but not saved.  Since I'm

I disagree. Please let the end user decide what we wants to do with
variable settings - wether he wants to save them or not.

> making an ACL, it seemed reasonable to implement that behavior
> generically.  The list behavior idea was an attempt at making the acl
> easier to change, since it would need to be changed (by users,
> scripts, and u-boot code) for several different use cases.

Ok, se your original intention was a scriptable "env edit" command,
which might (or might not) be based on some internal list
representation - but ther eis no need to introduce such a list to the
user interface.

> Run this command:
> 
> setenv a "\$x";printenv a;setenv b "$x";printenv b
> 
> Neither one ends up containing "$x".  I believe that the first one should.

There is some inconsistency in the environment variable subsituion,
indeed. Note that the example works with shell variables, though:

=> a="\$x"; b="$x"
=> echo a=${a} b=${b}
a=$x b=

For environment variables, you should delay/prevent variable
substitution using '...' quotes:

=> setenv a '\$x';printenv a;setenv b '$x';printenv b
a=$x
b=$x


Best regards,

Wolfgang Denk

-- 
DENX Software Engineering GmbH,     MD: Wolfgang Denk & Detlev Zundel
HRB 165235 Munich, Office: Kirchenstr.5, D-82194 Groebenzell, Germany
Phone: (+49)-8142-66989-10 Fax: (+49)-8142-66989-80 Email: wd at denx.de
Just about every computer on the market today runs Unix,  except  the
Mac (and nobody cares about it).                   - Bill Joy 6/21/85

^ permalink raw reply	[flat|nested] 124+ messages in thread

* [U-Boot] Read-only env variables
  2010-05-12  9:34                   ` Wolfgang Denk
@ 2010-05-12 23:46                     ` Joe Hershberger
  2010-06-22 21:18                       ` Wolfgang Denk
  0 siblings, 1 reply; 124+ messages in thread
From: Joe Hershberger @ 2010-05-12 23:46 UTC (permalink / raw)
  To: u-boot

On Wed, May 12, 2010 at 4:34 AM, Wolfgang Denk <wd@denx.de> wrote:
>> > There has been discussion about such a feature in the past. I even
>> > tried to define the user interface for such a command set, but
>> > unfortunately I didn't have enough time myself and nobody else took
>> > the bait either.
>>
>> Ok... if you can dig up the user interface you were thinking of, I can
>> compare it to what I've done and possibly tweak it. ?As it is now, I
>> intend to use the acl to define which variables are preserved. ?The
>> command takes no arguments and changes only the in-RAM environment.
>
> See here:
>
> http://thread.gmane.org/gmane.comp.boot-loaders.u-boot/36570/focus=36861

Looks like a reasonable user interface as far as the command layout.

> Taking this one step further, we should then also rename "editenv"
> into "env edit".

Why rename one existing command?  Why not rename askenv and the rest?
I don't think I would rename any of them or I would have a clear
separation and reason for renaming some and not others.

>> > Be careful. You are defining policy here, and actually you can do all
>> > this already now.
>>
>> I want the acl to be the one defining this policy.
>
> But this is IMHO wrong. The ACl should describe properties, i. e. if a
> variable can be written or not etc. ?It should NEVER try to define how
> the user deploys the properties of a variable.

It's a tool for the user to implement his chosen policy.  Instead of
writing a script to keep track of variables that have changed (that he
doesn't want to save) and having to call saveenv through a wrapper
script to process that list, it could be as simple as him adding that
to the ACL.

>> > Use "setenv ipaddr ...; saveenv" if the user wishes to change the
>> > static IP and write it to flash.
>>
>> Works great in a vacuum.
>
> ? What do you mean here?

Sorry... Nevermind.  Things are complicated by netconsole, but aren't
addressed by this anyway.

>> > Use "dhcp" (without "saveenv") to use dhcp to configure all the
>> > network settings without saving this to flash.
>>
>> In the case of dhcp, the key is that I want to be able to save some
>> unrelated change to the environment... I shouldn't be prevented from
>> doing it because I happened to configure the network already.
>
> I don't see your problem. If you want to define a default IP address
> and want to use this as "ipaddr" environment variable unless DHCP
> overwrites this value, then you can easily do that:
>
> ? ? ? ?=> setenv default_ipaddr aa.bb.cc.dd
> ? ? ? ?=> setenv default_netmask ...
> ? ? ? ?...
> ? ? ? ?=> setenv net_default 'setenv ipaddr ${default_ipaddr};setenv netmask ${default_netmask};...'
> ? ? ? ?=> setenv preboot run net_default

This is a reasonable approach and one that I have considered.

> How would you in your szenario, where "dhcp" can change the "ipaddr"
> environment variable, but a saveenv would not save it, set a new
> "ipaddr"?

Because the acl is editable, the user could simply change the lifetime
of the variable.  For best ease of use for this case, I've been
thinking of something like having the dhcp command mark the variables
it touches as volatile (see the bottom of this email) in the acl when
it touches them, and if they are touched by the setenv command line
interface, the volatile attribute is removed.  I wouldn't want all
variables that are marked as volatile to no longer be volatile when
accessed by setenv, so I would simply define a separate type called
auto-volatile that the dhcp command would utilize instead.  If setenv
command line sets an auto-volatile variable, then that variable loses
its volatile attribute.

> Me thinks you are adding complexity here without need, plus potential
> for lots of confusion.

It's true that you could currently choose to never call many of these
commands directly and always have wrapper scripts, but that's pretty
tedious and prevents you from having a familiar interface that comes
with using the commands directly.  I know I personally would take a
while to train myself to type "run saveenvcmd" instead of "saveenv".

While some things can be worked around, it doesn't mean they are a
easy to use.  Also, all behavior stays unchanged if you don't set the
ACL.  Like many things in u-boot, if a user is not interested, they
can just ignore the feature.

I'm curious what you think will be confusing?

>> > Well, then just do the saveenv _before_ you use DHCP. Or be careful
>>
>> Not possible for the use case... I'm using netconsole, so dhcp must be
>> first to make the console accessible... so no change made to the env
>> could ever be saved.
>
> OK, then do as described above and consider the variables set by DHCP
> as volatile and do not attempt to use these to store your default
> settings that are supposed to be persistent.

Again, I considered this possibility and have it on the back burner if
for some reason this is difficult to implement, but I don't like to
commit variables to flash that shouldn't be.

>> All of this stems from the fact that a number of env vars are magical.
>> ?Things like "ipaddr" and "stdin" etc. are hooked up to internals of
>> u-boot. ?In the case of stdin and family, the behavior (without
>> CONFIG_SYS_CONSOLE_IS_IN_ENV) is that those variables only affect the
>> run-time behavior and are not written to flash. ?I'm certain that the
>> reason for that is the same as the issue I'm having with the network
>
> No, the reason is more likely that the one who implemented this did
> just what he actually needed, without a clear concept for such a
> global scope. The next one who needed different behaviour added
> CONFIG_SYS_CONSOLE_IS_IN_ENV. Now we have both.

I guess my point is that the same need existed for other sub-systems,
and could be implemented generically with this in a consistent way
rather than one-off hacks for each case.

>> configuration. ?I think there should be a simple-to-use way to
>> indicate that a magical env var should be only magical and not in
>> flash or possibly initialized from flash but not saved. ?Since I'm
>
> I disagree. Please let the end user decide what we wants to do with
> variable settings - wether he wants to save them or not.

Exactly.  I'd like to give the user a simple way to chose which he
wants to save or not.  He should not need to manage it by writing
scripts that attempt to save off variables and restore them after the
env is written to flash.  Right now the user cannot decide.

>> making an ACL, it seemed reasonable to implement that behavior
>> generically. ?The list behavior idea was an attempt at making the acl
>> easier to change, since it would need to be changed (by users,
>> scripts, and u-boot code) for several different use cases.
>
> Ok, se your original intention was a scriptable "env edit" command,
> which might (or might not) be based on some internal list
> representation - but ther eis no need to introduce such a list to the
> user interface.

Fair enough.  Since the list management behavior was just to make
easier what I envisioned would be tedious, I've tabled that until I
try it out.

--------------

I've implemented the acl for type and access specification.  It
currently looks like this:

The first char in the attributes for a var in the acl is the type.  It can be:

    s - string (default)
    d - decimal
    x - hexadecimal
    b - boolean
    i - ip address
    m - ethernet mac address

The second char in the attributes for a var in the acl is the access
mode.  It can be:

    a - any (default, optional)
    r - read-only
    o - set once (this is create / change default)

I'm envisioning a third char in the attributes that is the lifetime.  It can be:

    p - precious (not removed on env default)
    v - volatile (not saved to flash)
    a - auto-volatile (not saved to flash, auto-cleared by setenv from
command line)

The fw_setenv Linux utility and the setenv command have the same
behavior and share the same code for implementing the acl.

In my initial playing with it, the experience feels like too much of
the detail that we want controlled is put in your face.  Things that
should just be a given such as the fact that ipaddr and ethaddr and a
number of other variables should have a certain type or be set-once or
whatever.  I think what will make it more reasonable to use is to have
a compiled in baseline acl, with a env var based augmentation.  That
way the user doesn't have to look at all the things that should just
always be.  It seems to be pretty much required from a usability
standpoint.

I'm also interested if you think it should be a compile time option to
support the ACL at all or if it should be added as a first class
citizen to permanently take the place of the curent hard-coded
behaviors.  I currently have it disabled at compile time (in u-boot,
not fw_env), but I also have not removed the other options it could
replace.

Best regards,
-Joe

^ permalink raw reply	[flat|nested] 124+ messages in thread

* [U-Boot] Read-only env variables
  2010-05-12 23:46                     ` Joe Hershberger
@ 2010-06-22 21:18                       ` Wolfgang Denk
  2010-06-22 21:49                         ` Joe Hershberger
  0 siblings, 1 reply; 124+ messages in thread
From: Wolfgang Denk @ 2010-06-22 21:18 UTC (permalink / raw)
  To: u-boot

Dear Joe Hershberger,

In message <AANLkTinCGpjd6x_Plgm4nkATlRNht83KFC8Xk2MNIK8d@mail.gmail.com> you wrote:
>
> > Taking this one step further, we should then also rename "editenv"
> > into "env edit".
> 
> Why rename one existing command?  Why not rename askenv and the rest?
> I don't think I would rename any of them or I would have a clear
> separation and reason for renaming some and not others.

Did you in any way start working on this?

FYI: I'm in the process of a bigger rewrite of the envrionment
handling code, which will, among other things, perform such a
renaming (keeping the old names in place, for compatibility, of
course).

> > But this is IMHO wrong. The ACl should describe properties, i. e. if a
> > variable can be written or not etc.  It should NEVER try to define how
> > the user deploys the properties of a variable.
> 
> It's a tool for the user to implement his chosen policy.  Instead of
> writing a script to keep track of variables that have changed (that he
> doesn't want to save) and having to call saveenv through a wrapper
> script to process that list, it could be as simple as him adding that
> to the ACL.

I think I'll address this situation from another side; in my new code
you will be able to export and import envrionment data; this way you
can for example save and restore snapshots of your environment
settings, and switch between several configurations easily. Also, you
can build your configuration by incrementally adding sets of
definitions.

> I've implemented the acl for type and access specification.  It
> currently looks like this:
>
> The first char in the attributes for a var in the acl is the type.  It can be:
>
>     s - string (default)
>     d - decimal
>     x - hexadecimal
>     b - boolean
>     i - ip address
>     m - ethernet mac address

You might want to add 'p' for pointers.

> I'm envisioning a third char in the attributes that is the lifetime.  It can be:
>
>     p - precious (not removed on env default)
>     v - volatile (not saved to flash)
>     a - auto-volatile (not saved to flash, auto-cleared by setenv from
> command line)

I did not get the concept of "auto-volatile". Please explain once
more.

> I'm also interested if you think it should be a compile time option to
> support the ACL at all or if it should be added as a first class
> citizen to permanently take the place of the curent hard-coded
> behaviors.  I currently have it disabled at compile time (in u-boot,
> not fw_env), but I also have not removed the other options it could
> replace.

I think we should make this a compile time option - and if it was for
the unavoidable additional memory footprint.

Best regards,

Wolfgang Denk

-- 
DENX Software Engineering GmbH,     MD: Wolfgang Denk & Detlev Zundel
HRB 165235 Munich, Office: Kirchenstr.5, D-82194 Groebenzell, Germany
Phone: (+49)-8142-66989-10 Fax: (+49)-8142-66989-80 Email: wd at denx.de
CAUTION:  The Mass of This Product Contains the Energy Equivalent  of
85 Million Tons of TNT per Net Ounce of Weight.

^ permalink raw reply	[flat|nested] 124+ messages in thread

* [U-Boot] Read-only env variables
  2010-06-22 21:18                       ` Wolfgang Denk
@ 2010-06-22 21:49                         ` Joe Hershberger
  2010-06-22 22:29                           ` Wolfgang Denk
  0 siblings, 1 reply; 124+ messages in thread
From: Joe Hershberger @ 2010-06-22 21:49 UTC (permalink / raw)
  To: u-boot

On Tue, Jun 22, 2010 at 4:18 PM, Wolfgang Denk <wd@denx.de> wrote:
>> > Taking this one step further, we should then also rename "editenv"
>> > into "env edit".
>>
>> Why rename one existing command? ?Why not rename askenv and the rest?
>> I don't think I would rename any of them or I would have a clear
>> separation and reason for renaming some and not others.
>
> Did you in any way start working on this?

I did not rename the commands yet... though I did implement 2/3 of the
ACL.  I never head back on which parts of the env handling should be
renamed and why.

> FYI: I'm in the process of a bigger rewrite of the envrionment
> handling code, which will, among other things, perform such a
> renaming (keeping the old names in place, for compatibility, of
> course).

So this means all aspects of the env handling would be under "env *"
including such things as printenv and setenv?  I like this so long as
the current commands remain for compatibility.

>> > But this is IMHO wrong. The ACl should describe properties, i. e. if a
>> > variable can be written or not etc. ?It should NEVER try to define how
>> > the user deploys the properties of a variable.
>>
>> It's a tool for the user to implement his chosen policy. ?Instead of
>> writing a script to keep track of variables that have changed (that he
>> doesn't want to save) and having to call saveenv through a wrapper
>> script to process that list, it could be as simple as him adding that
>> to the ACL.
>
> I think I'll address this situation from another side; in my new code
> you will be able to export and import envrionment data; this way you
> can for example save and restore snapshots of your environment
> settings, and switch between several configurations easily. Also, you
> can build your configuration by incrementally adding sets of
> definitions.

That sounds interesting.  Is there another thread where you've gone
into detail about this?

>> I've implemented the acl for type and access specification. ?It
>> currently looks like this:
>>
>> The first char in the attributes for a var in the acl is the type. ?It can be:
>>
>> ? ? s - string (default)
>> ? ? d - decimal
>> ? ? x - hexadecimal
>> ? ? b - boolean
>> ? ? i - ip address
>> ? ? m - ethernet mac address
>
> You might want to add 'p' for pointers.

How is this different than hexadecimal or decimal?  What would the
validation entail?

>> I'm envisioning a third char in the attributes that is the lifetime. ?It can be:
>>
>> ? ? p - precious (not removed on env default)
>> ? ? v - volatile (not saved to flash)
>> ? ? a - auto-volatile (not saved to flash, auto-cleared by setenv from
>> command line)
>
> I did not get the concept of "auto-volatile". Please explain once
> more.

I'll try to make it more clear with an example...  take ipaddr for
instance.  Your ACL has configured the ipaddr as "auto-volatile".
Your static IP address is stored in flash in ipaddr.  You boot and
decide you want DHCP, so you run "dhcp" to assign the ipaddr variable.
 You save your environment and the IP address that the DHCP server
gave you is not saved in the flash, it is only used for network
communication during this session.  The next time you boot, you get
your static IP back, since it was not overwritten in your flash.  You
then device that you would like to change your static IP address
setting.  When you call setenv some the command prompt (or a script),
the "auto-volatile" setting is removed from the ipaddr variable in the
ACL (the acl in RAM, not flash) which gives it the default behavior
that all variables have now.  Now when you save your environment, the
new ipaddr setting is saved into flash and available he next time you
boot.

>> I'm also interested if you think it should be a compile time option to
>> support the ACL at all or if it should be added as a first class
>> citizen to permanently take the place of the curent hard-coded
>> behaviors. ?I currently have it disabled at compile time (in u-boot,
>> not fw_env), but I also have not removed the other options it could
>> replace.
>
> I think we should make this a compile time option - and if it was for
> the unavoidable additional memory footprint.

So that means we should not remove the current ethaddr and serial#
write protection.

Best regards,
-Joe Hershberger

^ permalink raw reply	[flat|nested] 124+ messages in thread

* [U-Boot] Read-only env variables
  2010-06-22 21:49                         ` Joe Hershberger
@ 2010-06-22 22:29                           ` Wolfgang Denk
  2012-08-17 20:49                             ` [U-Boot] [PATCH 0/12] Add environment type checking and access control Joe Hershberger
  0 siblings, 1 reply; 124+ messages in thread
From: Wolfgang Denk @ 2010-06-22 22:29 UTC (permalink / raw)
  To: u-boot

Dear Joe Hershberger,

In message <AANLkTimi9FWMiaKkvm0RVgWSp5_uhHhTUtALZ9DbX0xy@mail.gmail.com> you wrote:
>
> So this means all aspects of the env handling would be under "env *"
> including such things as printenv and setenv?  I like this so long as
> the current commands remain for compatibility.

That's what I'm doing.

> That sounds interesting.  Is there another thread where you've gone
> into detail about this?

No, not yet. I'm still experimenting with the design; I would like to
know a little better myself what I want to do before I start
discussing it :-)

> >>     s - string (default)
> >>     d - decimal
> >>     x - hexadecimal
> >>     b - boolean
> >>     i - ip address
> >>     m - ethernet mac address
> >
> > You might want to add 'p' for pointers.
> 
> How is this different than hexadecimal or decimal?  What would the
> validation entail?

For 'd' and 'x' I would expect to see the equivalent of an "unsigned
long" as underlying data type; for 'p' we should probably use a
"physaddr_t" which might be > 32 bit even on 32 bit systems.

> > I did not get the concept of "auto-volatile". Please explain once
> > more.
> 
> I'll try to make it more clear with an example...  take ipaddr for
> instance.  Your ACL has configured the ipaddr as "auto-volatile".
> Your static IP address is stored in flash in ipaddr.  You boot and
> decide you want DHCP, so you run "dhcp" to assign the ipaddr variable.
>  You save your environment and the IP address that the DHCP server
> gave you is not saved in the flash, it is only used for network
> communication during this session.  The next time you boot, you get
> your static IP back, since it was not overwritten in your flash.  You
> then device that you would like to change your static IP address
> setting.  When you call setenv some the command prompt (or a script),
> the "auto-volatile" setting is removed from the ipaddr variable in the
> ACL (the acl in RAM, not flash) which gives it the default behavior
> that all variables have now.  Now when you save your environment, the
> new ipaddr setting is saved into flash and available he next time you
> boot.

You mean the setenv() called from the DHCP code would behave
differently than the setenv() called from the command line? Now that
_is_ confusing to me. I doubt many users will understand what's going
on on such a system.

> > I think we should make this a compile time option - and if it was for
> > the unavoidable additional memory footprint.
> 
> So that means we should not remove the current ethaddr and serial#
> write protection.

Not if it can be avoided easily. OTOH my new code will have commands
like "env default" or "env import" which will not care at all about
these variables, but simply do what you asked for. Dunno if this will
need to be changed - but if so, then I'd rather to this in the context
of a new read-only concept.

Best regards,

Wolfgang Denk

-- 
DENX Software Engineering GmbH,     MD: Wolfgang Denk & Detlev Zundel
HRB 165235 Munich, Office: Kirchenstr.5, D-82194 Groebenzell, Germany
Phone: (+49)-8142-66989-10 Fax: (+49)-8142-66989-80 Email: wd at denx.de
As far as we know, our computer has never had an undetected error.
		                                           -- Weisert

^ permalink raw reply	[flat|nested] 124+ messages in thread

* [U-Boot] [PATCH 0/12] Add environment type checking and access control
  2010-06-22 22:29                           ` Wolfgang Denk
@ 2012-08-17 20:49                             ` Joe Hershberger
  2012-08-17 20:49                               ` [U-Boot] [PATCH 01/12] tools/env: Use a board-specific default env Joe Hershberger
                                                 ` (12 more replies)
  0 siblings, 13 replies; 124+ messages in thread
From: Joe Hershberger @ 2012-08-17 20:49 UTC (permalink / raw)
  To: u-boot


Enable validation of the values given to enviroment variables when
calling env set.  Variables can be restricted to only decimal,
hexadecimal, or boolean.  If CONFIG_CMD_NET is also defined,
the variables can also be restricted to IP address or MAC address.

The format of the list is:
        type_attribute = [s|d|x|b|i|m]
        access_atribute = [a|r|o]
        attributes = type_attribute[access_atribute]
        entry = variable_name[:attributes]
        list = entry[,list]

The type attributes are:
        s - String (default)
        d - Decimal
        x - Hexadecimal
        b - Boolean
        i - IP address
        m - MAC address

The access attributes are:
        a - Any (default)
        r - Read-only
        o - Write-once (change default)

- CONFIG_ENV_ACL_DEFAULT
        Define this to a list (string) to define the "acl" envirnoment
        variable in the default or embedded environment.

- CONFIG_ENV_ACL_STATIC
        Define this to a list (string) to define validation that
        should be done if an entry is not found in the "acl"
        environment variable.  To override a setting in the static
        list, simply add an entry for the same variable name to the
        "acl" variable.


Joe Hershberger (12):
  tools/env: Use a board-specific default env
  tools/env: Remove unneeded complexity
  tools/env: Don't call env_init() in fw_getenv()
  tools/env: Reduce the impact on real-time processes
  tools/env: Serialize calls to fw_*env
  env: Make the "silent" env var take effect immediately
  env: Update serial baudrate in env_relocate()
  env: Check for NULL pointer in envmatch()
  env: Clarify the cases for env set
  env: acl: Add environment variable access control list
  env: acl: Add support for access control to env ACL
  env: cosmetic: Consilidate the default env definition

 README                  |  42 +++++++
 common/Makefile         |   1 +
 common/cmd_nvedit.c     | 171 ++++++++++++++++++++-------
 common/env_acl.c        | 308 ++++++++++++++++++++++++++++++++++++++++++++++++
 common/env_common.c     | 123 +++++--------------
 common/env_embedded.c   | 111 +----------------
 doc/README.silent       |  14 ++-
 include/env_acl.h       |  63 ++++++++++
 include/env_default.h   | 142 ++++++++++++++++++++++
 tools/env/Makefile      |   7 +-
 tools/env/fw_env.c      | 305 ++++++++++++++++++++++++-----------------------
 tools/env/fw_env.h      |  25 ++++
 tools/env/fw_env_main.c |  59 ++++++----
 13 files changed, 943 insertions(+), 428 deletions(-)
 create mode 100644 common/env_acl.c
 create mode 100644 include/env_acl.h
 create mode 100644 include/env_default.h

-- 
1.7.11.5

^ permalink raw reply	[flat|nested] 124+ messages in thread

* [U-Boot] [PATCH 01/12] tools/env: Use a board-specific default env
  2012-08-17 20:49                             ` [U-Boot] [PATCH 0/12] Add environment type checking and access control Joe Hershberger
@ 2012-08-17 20:49                               ` Joe Hershberger
  2012-08-23  3:17                                 ` Mike Frysinger
  2012-08-17 20:49                               ` [U-Boot] [PATCH 02/12] tools/env: Remove unneeded complexity Joe Hershberger
                                                 ` (11 subsequent siblings)
  12 siblings, 1 reply; 124+ messages in thread
From: Joe Hershberger @ 2012-08-17 20:49 UTC (permalink / raw)
  To: u-boot

Originally added in aa701b94336b358798d676eef12a7b90bdac23f5

Before this patch, there was a hard-coded env that was used as default
if the env in flash is detected as invalid.  Now this tool (compiled
for a given board) will share the default env with the u-boot for the
board.

Fix include of config.h

Need to define "TEXT_BASE" when building the fw_env tool so that the
default env will be correct for environments which use it.

Define __ASSEMBLY__ when calling #include <config.h> so that we only
get #defines (all we're interested in).

Signed-off-by: Joe Hershberger <joe.hershberger@ni.com>
---
 tools/env/Makefile |  5 +++--
 tools/env/fw_env.c | 28 +++++++++++++---------------
 tools/env/fw_env.h | 19 +++++++++++++++++++
 3 files changed, 35 insertions(+), 17 deletions(-)

diff --git a/tools/env/Makefile b/tools/env/Makefile
index 07634bc..ab73c8c 100644
--- a/tools/env/Makefile
+++ b/tools/env/Makefile
@@ -24,13 +24,14 @@
 include $(TOPDIR)/config.mk
 
 HOSTSRCS := $(SRCTREE)/lib/crc32.c  fw_env.c  fw_env_main.c
-HEADERS	:= fw_env.h
+HEADERS	:= fw_env.h $(OBJTREE)/include/config.h
 
 # Compile for a hosted environment on the target
 HOSTCPPFLAGS  = -idirafter $(SRCTREE)/include \
 		-idirafter $(OBJTREE)/include2 \
 		-idirafter $(OBJTREE)/include \
-		-DUSE_HOSTCC
+		-DUSE_HOSTCC \
+		-DTEXT_BASE=$(TEXT_BASE)
 
 ifeq ($(MTD_VERSION),old)
 HOSTCPPFLAGS += -DMTD_OLD
diff --git a/tools/env/fw_env.c b/tools/env/fw_env.c
index e292d2b..e46791d 100644
--- a/tools/env/fw_env.c
+++ b/tools/env/fw_env.c
@@ -45,8 +45,6 @@
 
 #include "fw_env.h"
 
-#include <config.h>
-
 #define WHITESPACE(c) ((c == '\t') || (c == ' '))
 
 #define min(x, y) ({				\
@@ -81,7 +79,7 @@ static int dev_current;
 #define ENVSECTORS(i) envdevices[(i)].env_sectors
 #define DEVTYPE(i)    envdevices[(i)].mtd_type
 
-#define CONFIG_ENV_SIZE ENVSIZE(dev_current)
+#define CUR_ENVSIZE ENVSIZE(dev_current)
 
 #define ENV_SIZE      getenvsize()
 
@@ -218,7 +216,7 @@ static int get_config (char *);
 #endif
 static inline ulong getenvsize (void)
 {
-	ulong rc = CONFIG_ENV_SIZE - sizeof (long);
+	ulong rc = CUR_ENVSIZE - sizeof(long);
 
 	if (HaveRedundEnv)
 		rc -= sizeof (char);
@@ -434,7 +432,7 @@ int fw_env_write(char *name, char *value)
 		++env;
 	/*
 	 * Overflow when:
-	 * "name" + "=" + "val" +"\0\0"  > CONFIG_ENV_SIZE - (env-environment)
+	 * "name" + "=" + "val" +"\0\0"  > CUR_ENVSIZE - (env-environment)
 	 */
 	len = strlen (name) + 2;
 	/* add '=' for first arg, ' ' for all others */
@@ -949,8 +947,8 @@ static int flash_write (int fd_current, int fd_target, int dev_target)
 	printf ("Writing new environment at 0x%lx on %s\n",
 		DEVOFFSET (dev_target), DEVNAME (dev_target));
 #endif
-	rc = flash_write_buf (dev_target, fd_target, environment.image,
-			      CONFIG_ENV_SIZE, DEVOFFSET (dev_target),
+	rc = flash_write_buf(dev_target, fd_target, environment.image,
+			      CUR_ENVSIZE, DEVOFFSET(dev_target),
 			      DEVTYPE(dev_target));
 	if (rc < 0)
 		return rc;
@@ -989,10 +987,10 @@ static int flash_read (int fd)
 
 	DEVTYPE(dev_current) = mtdinfo.type;
 
-	rc = flash_read_buf (dev_current, fd, environment.image, CONFIG_ENV_SIZE,
+	rc = flash_read_buf(dev_current, fd, environment.image, CUR_ENVSIZE,
 			     DEVOFFSET (dev_current), mtdinfo.type);
 
-	return (rc != CONFIG_ENV_SIZE) ? -1 : 0;
+	return (rc != CUR_ENVSIZE) ? -1 : 0;
 }
 
 static int flash_io (int mode)
@@ -1089,11 +1087,11 @@ int fw_env_open(void)
 	if (parse_config ())		/* should fill envdevices */
 		return -1;
 
-	addr0 = calloc (1, CONFIG_ENV_SIZE);
+	addr0 = calloc(1, CUR_ENVSIZE);
 	if (addr0 == NULL) {
-		fprintf (stderr,
+		fprintf(stderr,
 			"Not enough memory for environment (%ld bytes)\n",
-			CONFIG_ENV_SIZE);
+			CUR_ENVSIZE);
 		return -1;
 	}
 
@@ -1128,11 +1126,11 @@ int fw_env_open(void)
 		flag0 = *environment.flags;
 
 		dev_current = 1;
-		addr1 = calloc (1, CONFIG_ENV_SIZE);
+		addr1 = calloc(1, CUR_ENVSIZE);
 		if (addr1 == NULL) {
-			fprintf (stderr,
+			fprintf(stderr,
 				"Not enough memory for environment (%ld bytes)\n",
-				CONFIG_ENV_SIZE);
+				CUR_ENVSIZE);
 			return -1;
 		}
 		redundant = addr1;
diff --git a/tools/env/fw_env.h b/tools/env/fw_env.h
index ad32446..a1a6807 100644
--- a/tools/env/fw_env.h
+++ b/tools/env/fw_env.h
@@ -21,6 +21,15 @@
  * MA 02111-1307 USA
  */
 
+/* Pull in the current config to define the default environment */
+#ifndef __ASSEMBLY__
+#define __ASSEMBLY__ /* get only #defines from config.h */
+#include <config.h>
+#undef	__ASSEMBLY__
+#else
+#include <config.h>
+#endif
+
 /*
  * To build the utility with the static configuration
  * comment out the next line.
@@ -29,6 +38,7 @@
  */
 #define CONFIG_FILE     "/etc/fw_env.config"
 
+#ifndef CONFIG_FILE
 #define HAVE_REDUND /* For systems with 2 env sectors */
 #define DEVICE1_NAME      "/dev/mtd1"
 #define DEVICE2_NAME      "/dev/mtd2"
@@ -40,14 +50,23 @@
 #define ENV2_SIZE         0x4000
 #define DEVICE2_ESIZE     0x4000
 #define DEVICE2_ENVSECTORS     2
+#endif
 
+#ifndef CONFIG_BAUDRATE
 #define CONFIG_BAUDRATE		115200
+#endif
+
+#ifndef CONFIG_BOOTDELAY
 #define CONFIG_BOOTDELAY	5	/* autoboot after 5 seconds	*/
+#endif
+
+#ifndef CONFIG_BOOTCOMMAND
 #define CONFIG_BOOTCOMMAND							\
 	"bootp; "								\
 	"setenv bootargs root=/dev/nfs nfsroot=${serverip}:${rootpath} "	\
 	"ip=${ipaddr}:${serverip}:${gatewayip}:${netmask}:${hostname}::off; "	\
 	"bootm"
+#endif
 
 extern int   fw_printenv(int argc, char *argv[]);
 extern char *fw_getenv  (char *name);
-- 
1.7.11.5

^ permalink raw reply related	[flat|nested] 124+ messages in thread

* [U-Boot] [PATCH 02/12] tools/env: Remove unneeded complexity
  2012-08-17 20:49                             ` [U-Boot] [PATCH 0/12] Add environment type checking and access control Joe Hershberger
  2012-08-17 20:49                               ` [U-Boot] [PATCH 01/12] tools/env: Use a board-specific default env Joe Hershberger
@ 2012-08-17 20:49                               ` Joe Hershberger
  2012-08-23  3:30                                 ` Mike Frysinger
  2012-08-17 20:49                               ` [U-Boot] [PATCH 03/12] tools/env: Don't call env_init() in fw_getenv() Joe Hershberger
                                                 ` (10 subsequent siblings)
  12 siblings, 1 reply; 124+ messages in thread
From: Joe Hershberger @ 2012-08-17 20:49 UTC (permalink / raw)
  To: u-boot

The length included the name length, and then it was subtracted back
out on each use.  Now we don't include it in the first place.

Signed-off-by: Joe Hershberger <joe.hershberger@ni.com>
---
 tools/env/fw_env.c | 9 +++++----
 1 file changed, 5 insertions(+), 4 deletions(-)

diff --git a/tools/env/fw_env.c b/tools/env/fw_env.c
index e46791d..a461dbd 100644
--- a/tools/env/fw_env.c
+++ b/tools/env/fw_env.c
@@ -484,22 +484,23 @@ int fw_setenv(int argc, char *argv[])
 
 	name = argv[1];
 
-	len = strlen(name) + 2;
+	len = 0;
 	for (i = 2; i < argc; ++i)
 		len += strlen(argv[i]) + 1;
 
 	/* Allocate enough place to the data string */
 	for (i = 2; i < argc; ++i) {
 		char *val = argv[i];
+
 		if (!value) {
-			value = (char *)malloc(len - strlen(name));
+			value = (char *)malloc(len);
 			if (!value) {
 				fprintf(stderr,
 				"Cannot malloc %zu bytes: %s\n",
-				len - strlen(name), strerror(errno));
+				len, strerror(errno));
 				return -1;
 			}
-			memset(value, 0, len - strlen(name));
+			memset(value, 0, len);
 			tmpval = value;
 		}
 		if (i != 2)
-- 
1.7.11.5

^ permalink raw reply related	[flat|nested] 124+ messages in thread

* [U-Boot] [PATCH 03/12] tools/env: Don't call env_init() in fw_getenv()
  2012-08-17 20:49                             ` [U-Boot] [PATCH 0/12] Add environment type checking and access control Joe Hershberger
  2012-08-17 20:49                               ` [U-Boot] [PATCH 01/12] tools/env: Use a board-specific default env Joe Hershberger
  2012-08-17 20:49                               ` [U-Boot] [PATCH 02/12] tools/env: Remove unneeded complexity Joe Hershberger
@ 2012-08-17 20:49                               ` Joe Hershberger
  2012-08-17 20:49                               ` [U-Boot] [PATCH 04/12] tools/env: Reduce the impact on real-time processes Joe Hershberger
                                                 ` (9 subsequent siblings)
  12 siblings, 0 replies; 124+ messages in thread
From: Joe Hershberger @ 2012-08-17 20:49 UTC (permalink / raw)
  To: u-boot

We will only call fw_getenv when the env has already been initialized.

Signed-off-by: Joe Hershberger <joe.hershberger@ni.com>
---
 tools/env/fw_env.c | 3 ---
 1 file changed, 3 deletions(-)

diff --git a/tools/env/fw_env.c b/tools/env/fw_env.c
index a461dbd..8bb7f9a 100644
--- a/tools/env/fw_env.c
+++ b/tools/env/fw_env.c
@@ -247,9 +247,6 @@ char *fw_getenv (char *name)
 {
 	char *env, *nxt;
 
-	if (fw_env_open())
-		return NULL;
-
 	for (env = environment.data; *env; env = nxt + 1) {
 		char *val;
 
-- 
1.7.11.5

^ permalink raw reply related	[flat|nested] 124+ messages in thread

* [U-Boot] [PATCH 04/12] tools/env: Reduce the impact on real-time processes
  2012-08-17 20:49                             ` [U-Boot] [PATCH 0/12] Add environment type checking and access control Joe Hershberger
                                                 ` (2 preceding siblings ...)
  2012-08-17 20:49                               ` [U-Boot] [PATCH 03/12] tools/env: Don't call env_init() in fw_getenv() Joe Hershberger
@ 2012-08-17 20:49                               ` Joe Hershberger
  2012-08-23  3:30                                 ` Mike Frysinger
  2012-08-17 20:49                               ` [U-Boot] [PATCH 05/12] tools/env: Serialize calls to fw_*env Joe Hershberger
                                                 ` (8 subsequent siblings)
  12 siblings, 1 reply; 124+ messages in thread
From: Joe Hershberger @ 2012-08-17 20:49 UTC (permalink / raw)
  To: u-boot

Modify fw_printenv to read in chunks of 0x20 at a time.

Signed-off-by: Joe Hershberger <joe.hershberger@ni.com>
---
 tools/env/fw_env.c | 25 ++++++++++++++++++++-----
 1 file changed, 20 insertions(+), 5 deletions(-)

diff --git a/tools/env/fw_env.c b/tools/env/fw_env.c
index 8bb7f9a..9ecc22a 100644
--- a/tools/env/fw_env.c
+++ b/tools/env/fw_env.c
@@ -45,6 +45,8 @@
 
 #include "fw_env.h"
 
+#define MAX_BYTES_PER_READ 0x20
+
 #define WHITESPACE(c) ((c == '\t') || (c == ' '))
 
 #define min(x, y) ({				\
@@ -671,6 +673,7 @@ static int flash_read_buf (int dev, int fd, void *buf, size_t count,
 	size_t blocklen;	/* erase / write length - one block on NAND,
 				   0 on NOR */
 	size_t processed = 0;	/* progress counter */
+	size_t bytesread = 0;	/* bytes read so far */
 	size_t readlen = count;	/* current read length */
 	off_t top_of_range;	/* end of the last block we may use */
 	off_t block_seek;	/* offset inside the current block to the start
@@ -730,11 +733,23 @@ static int flash_read_buf (int dev, int fd, void *buf, size_t count,
 		 */
 		lseek (fd, blockstart + block_seek, SEEK_SET);
 
-		rc = read (fd, buf + processed, readlen);
-		if (rc != readlen) {
-			fprintf (stderr, "Read error on %s: %s\n",
-				 DEVNAME (dev), strerror (errno));
-			return -1;
+		/*
+		* Break reads up into very small chunks so fw_printenv doesn't
+		* block the kernel long enough to starve other kernel tasks.
+		*/
+		bytesread = 0;
+		while (bytesread < readlen) {
+			size_t bytestoread = readlen - bytesread;
+
+			if (bytestoread > MAX_BYTES_PER_READ)
+				bytestoread = MAX_BYTES_PER_READ;
+			rc = read(fd, buf + processed + bytesread, bytestoread);
+			if (rc != bytestoread) {
+				fprintf(stderr, "Read error on %s: %s\n",
+					 DEVNAME(dev), strerror(errno));
+				return -1;
+			}
+			bytesread += bytestoread;
 		}
 #ifdef DEBUG
 		fprintf (stderr, "Read 0x%x bytes at 0x%llx\n",
-- 
1.7.11.5

^ permalink raw reply related	[flat|nested] 124+ messages in thread

* [U-Boot] [PATCH 05/12] tools/env: Serialize calls to fw_*env
  2012-08-17 20:49                             ` [U-Boot] [PATCH 0/12] Add environment type checking and access control Joe Hershberger
                                                 ` (3 preceding siblings ...)
  2012-08-17 20:49                               ` [U-Boot] [PATCH 04/12] tools/env: Reduce the impact on real-time processes Joe Hershberger
@ 2012-08-17 20:49                               ` Joe Hershberger
  2012-08-23  3:33                                 ` Mike Frysinger
  2012-08-17 20:49                               ` [U-Boot] [PATCH 06/12] env: Make the "silent" env var take effect immediately Joe Hershberger
                                                 ` (7 subsequent siblings)
  12 siblings, 1 reply; 124+ messages in thread
From: Joe Hershberger @ 2012-08-17 20:49 UTC (permalink / raw)
  To: u-boot

Use a lock file at /var/lock/fw_printenv.lock.
Avoids seriously confusing the MTD driver.

Signed-off-by: Joe Hershberger <joe.hershberger@ni.com>
---
 tools/env/fw_env_main.c | 59 +++++++++++++++++++++++++++++++------------------
 1 file changed, 37 insertions(+), 22 deletions(-)

diff --git a/tools/env/fw_env_main.c b/tools/env/fw_env_main.c
index c654057..c855f4c 100644
--- a/tools/env/fw_env_main.c
+++ b/tools/env/fw_env_main.c
@@ -39,10 +39,13 @@
  *		  variable "name"
  */
 
+#include <fcntl.h>
+#include <getopt.h>
 #include <stdio.h>
 #include <string.h>
 #include <stdlib.h>
-#include <getopt.h>
+#include <sys/file.h>
+#include <unistd.h>
 #include "fw_env.h"
 
 #define	CMD_PRINTENV	"fw_printenv"
@@ -81,13 +84,27 @@ void usage(void)
 	);
 }
 
-int
-main(int argc, char *argv[])
+int main(int argc, char *argv[])
 {
 	char *p;
 	char *cmdname = *argv;
 	char *script_file = NULL;
 	int c;
+	const char *lockname = "/var/lock/" CMD_PRINTENV ".lock";
+	int lockfd = -1;
+	int retval = EXIT_SUCCESS;
+
+	lockfd = open(lockname, O_WRONLY | O_CREAT | O_TRUNC);
+	if (-1 == lockfd) {
+		fprintf(stderr, "Error opening lock file %s\n", lockname);
+		return EXIT_FAILURE;
+	}
+
+	if (-1 == flock(lockfd, LOCK_EX)) {
+		fprintf(stderr, "Error locking file %s\n", lockname);
+		close(lockfd);
+		return EXIT_FAILURE;
+	}
 
 	if ((p = strrchr (cmdname, '/')) != NULL) {
 		cmdname = p + 1;
@@ -104,38 +121,36 @@ main(int argc, char *argv[])
 			break;
 		case 'h':
 			usage();
-			return EXIT_SUCCESS;
+			goto exit;
 		default: /* '?' */
 			fprintf(stderr, "Try `%s --help' for more information."
 				"\n", cmdname);
-			return EXIT_FAILURE;
+			retval = EXIT_FAILURE;
+			goto exit;
 		}
 	}
 
-
 	if (strcmp(cmdname, CMD_PRINTENV) == 0) {
-
-		if (fw_printenv (argc, argv) != 0)
-			return EXIT_FAILURE;
-
-		return EXIT_SUCCESS;
-
+		if (fw_printenv(argc, argv) != 0)
+			retval = EXIT_FAILURE;
 	} else if (strcmp(cmdname, CMD_SETENV) == 0) {
 		if (!script_file) {
 			if (fw_setenv(argc, argv) != 0)
-				return EXIT_FAILURE;
+				retval = EXIT_FAILURE;
 		} else {
 			if (fw_parse_script(script_file) != 0)
-				return EXIT_FAILURE;
+				retval = EXIT_FAILURE;
 		}
-
-		return EXIT_SUCCESS;
-
+	} else {
+		fprintf(stderr,
+			"Identity crisis - may be called as `" CMD_PRINTENV
+			"' or as `" CMD_SETENV "' but not as `%s'\n",
+			cmdname);
+		retval = EXIT_FAILURE;
 	}
 
-	fprintf (stderr,
-		"Identity crisis - may be called as `" CMD_PRINTENV
-		"' or as `" CMD_SETENV "' but not as `%s'\n",
-		cmdname);
-	return EXIT_FAILURE;
+exit:
+	flock(lockfd, LOCK_UN);
+	close(lockfd);
+	return retval;
 }
-- 
1.7.11.5

^ permalink raw reply related	[flat|nested] 124+ messages in thread

* [U-Boot] [PATCH 06/12] env: Make the "silent" env var take effect immediately
  2012-08-17 20:49                             ` [U-Boot] [PATCH 0/12] Add environment type checking and access control Joe Hershberger
                                                 ` (4 preceding siblings ...)
  2012-08-17 20:49                               ` [U-Boot] [PATCH 05/12] tools/env: Serialize calls to fw_*env Joe Hershberger
@ 2012-08-17 20:49                               ` Joe Hershberger
  2012-08-23  3:35                                 ` Mike Frysinger
  2012-08-17 20:49                               ` [U-Boot] [PATCH 07/12] env: Update serial baudrate in env_relocate() Joe Hershberger
                                                 ` (6 subsequent siblings)
  12 siblings, 1 reply; 124+ messages in thread
From: Joe Hershberger @ 2012-08-17 20:49 UTC (permalink / raw)
  To: u-boot

The silent variable now updates the global data flag anytime it is
changed as well as after the env relocation (in case its value is
different from the default env in such cases as NAND env)

Signed-off-by: Joe Hershberger <joe.hershberger@ni.com>
---
 common/cmd_nvedit.c | 16 ++++++++++++++++
 common/env_common.c |  8 ++++++++
 doc/README.silent   | 14 ++++++++++----
 3 files changed, 34 insertions(+), 4 deletions(-)

diff --git a/common/cmd_nvedit.c b/common/cmd_nvedit.c
index fd05e72..bd52fa4 100644
--- a/common/cmd_nvedit.c
+++ b/common/cmd_nvedit.c
@@ -303,9 +303,25 @@ int _do_env_set(int flag, int argc, char * const argv[])
 	/* Delete only ? */
 	if (argc < 3 || argv[2] == NULL) {
 		int rc = hdelete_r(name, &env_htab);
+
+#if defined(CONFIG_SILENT_CONSOLE) && \
+	defined(CONFIG_SILENT_CONSOLE_UPDATE_ON_SET)
+		if (strcmp(name, "silent") == 0) {
+			/* silent is deleted */
+			gd->flags &= ~GD_FLG_SILENT;
+		}
+#endif
 		return !rc;
 	}
 
+#if defined(CONFIG_SILENT_CONSOLE) && \
+	defined(CONFIG_SILENT_CONSOLE_UPDATE_ON_SET)
+	if (strcmp(name, "silent") == 0) {
+		/* silent is added */
+		gd->flags |= GD_FLG_SILENT;
+	}
+#endif
+
 	/*
 	 * Insert / replace new value
 	 */
diff --git a/common/env_common.c b/common/env_common.c
index d9e990d..0c7e845 100644
--- a/common/env_common.c
+++ b/common/env_common.c
@@ -245,6 +245,14 @@ void env_relocate(void)
 	} else {
 		env_relocate_spec();
 	}
+
+#if defined(CONFIG_SILENT_CONSOLE) && \
+	defined(CONFIG_SILENT_CONSOLE_UPDATE_ON_RELOC)
+	if (getenv("silent") != NULL)
+		gd->flags |= GD_FLG_SILENT;
+	else
+		gd->flags &= ~GD_FLG_SILENT;
+#endif
 }
 
 #ifdef CONFIG_AUTO_COMPLETE
diff --git a/doc/README.silent b/doc/README.silent
index a26e3df..a04961f 100644
--- a/doc/README.silent
+++ b/doc/README.silent
@@ -1,9 +1,15 @@
 The config option CONFIG_SILENT_CONSOLE can be used to quiet messages
 on the console.  If the option has been enabled, the output can be
-silenced by setting the environment variable "silent".  The variable
-is latched into the global data at an early stage in the boot process
-so deleting it with "setenv" will not take effect until the system is
-restarted.
+silenced by setting the environment variable "silent".
+
+- CONFIG_SILENT_CONSOLE_UPDATE_ON_SET
+	When the "silent" variable is changed with env set, the change
+	will take effect immediately
+
+- CONFIG_SILENT_CONSOLE_UPDATE_ON_RELOC
+	Some environments are not available until relocation (e.g. NAND)
+	so this will make the value in the flash env take effect at
+	relocation.
 
 The following actions are taken if "silent" is set at boot time:
 
-- 
1.7.11.5

^ permalink raw reply related	[flat|nested] 124+ messages in thread

* [U-Boot] [PATCH 07/12] env: Update serial baudrate in env_relocate()
  2012-08-17 20:49                             ` [U-Boot] [PATCH 0/12] Add environment type checking and access control Joe Hershberger
                                                 ` (5 preceding siblings ...)
  2012-08-17 20:49                               ` [U-Boot] [PATCH 06/12] env: Make the "silent" env var take effect immediately Joe Hershberger
@ 2012-08-17 20:49                               ` Joe Hershberger
  2012-08-17 20:49                               ` [U-Boot] [PATCH 08/12] env: Check for NULL pointer in envmatch() Joe Hershberger
                                                 ` (5 subsequent siblings)
  12 siblings, 0 replies; 124+ messages in thread
From: Joe Hershberger @ 2012-08-17 20:49 UTC (permalink / raw)
  To: u-boot

After the env is relocated, make sure that the serial baudrate is
applied in case it's different (such as the env_nand case).

Signed-off-by: Joe Hershberger <joe.hershberger@ni.com>
---
 common/env_common.c | 19 +++++++++++++++++++
 1 file changed, 19 insertions(+)

diff --git a/common/env_common.c b/common/env_common.c
index 0c7e845..e58971d 100644
--- a/common/env_common.c
+++ b/common/env_common.c
@@ -232,6 +232,10 @@ int env_import(const char *buf, int check)
 
 void env_relocate(void)
 {
+#ifdef CONFIG_BAUDRATE_UPDATE_ON_RELOC
+	const char *baudrate_str;
+#endif
+
 #if defined(CONFIG_NEEDS_MANUAL_RELOC)
 	env_reloc();
 #endif
@@ -253,6 +257,21 @@ void env_relocate(void)
 	else
 		gd->flags &= ~GD_FLG_SILENT;
 #endif
+
+#ifdef CONFIG_BAUDRATE_UPDATE_ON_RELOC
+	baudrate_str = getenv("baudrate");
+	if (baudrate_str != NULL) {
+		int baudrate = simple_strtoul(baudrate_str, NULL, 10);
+
+		if (baudrate != gd->baudrate) {
+			gd->baudrate = baudrate;
+#if defined(CONFIG_PPC) || defined(CONFIG_MCF52x2)
+			gd->bd->bi_baudrate = baudrate;
+#endif
+			serial_setbrg();
+		}
+	}
+#endif
 }
 
 #ifdef CONFIG_AUTO_COMPLETE
-- 
1.7.11.5

^ permalink raw reply related	[flat|nested] 124+ messages in thread

* [U-Boot] [PATCH 08/12] env: Check for NULL pointer in envmatch()
  2012-08-17 20:49                             ` [U-Boot] [PATCH 0/12] Add environment type checking and access control Joe Hershberger
                                                 ` (6 preceding siblings ...)
  2012-08-17 20:49                               ` [U-Boot] [PATCH 07/12] env: Update serial baudrate in env_relocate() Joe Hershberger
@ 2012-08-17 20:49                               ` Joe Hershberger
  2012-08-17 23:51                                 ` Mike Frysinger
  2012-08-17 20:49                               ` [U-Boot] [PATCH 09/12] env: Clarify the cases for env set Joe Hershberger
                                                 ` (4 subsequent siblings)
  12 siblings, 1 reply; 124+ messages in thread
From: Joe Hershberger @ 2012-08-17 20:49 UTC (permalink / raw)
  To: u-boot

If the pointer passed into envmatch() is NULL, return -1 instead of
crashing.

Signed-off-by: Joe Hershberger <joe.hershberger@ni.com>
---
 common/cmd_nvedit.c | 3 +++
 tools/env/fw_env.c  | 2 ++
 2 files changed, 5 insertions(+)

diff --git a/common/cmd_nvedit.c b/common/cmd_nvedit.c
index bd52fa4..76cdd87 100644
--- a/common/cmd_nvedit.c
+++ b/common/cmd_nvedit.c
@@ -619,6 +619,9 @@ U_BOOT_CMD(
  */
 int envmatch(uchar *s1, int i2)
 {
+	if (s1 == NULL)
+		return -1;
+
 	while (*s1 == env_get_char(i2++))
 		if (*s1++ == '=')
 			return i2;
diff --git a/tools/env/fw_env.c b/tools/env/fw_env.c
index 9ecc22a..23cf241 100644
--- a/tools/env/fw_env.c
+++ b/tools/env/fw_env.c
@@ -1072,6 +1072,8 @@ exit:
 
 static char *envmatch (char * s1, char * s2)
 {
+	if (s1 == NULL || s2 == NULL)
+		return NULL;
 
 	while (*s1 == *s2++)
 		if (*s1++ == '=')
-- 
1.7.11.5

^ permalink raw reply related	[flat|nested] 124+ messages in thread

* [U-Boot] [PATCH 09/12] env: Clarify the cases for env set
  2012-08-17 20:49                             ` [U-Boot] [PATCH 0/12] Add environment type checking and access control Joe Hershberger
                                                 ` (7 preceding siblings ...)
  2012-08-17 20:49                               ` [U-Boot] [PATCH 08/12] env: Check for NULL pointer in envmatch() Joe Hershberger
@ 2012-08-17 20:49                               ` Joe Hershberger
  2012-08-17 20:49                               ` [U-Boot] [PATCH 10/12] env: acl: Add environment variable access control list Joe Hershberger
                                                 ` (3 subsequent siblings)
  12 siblings, 0 replies; 124+ messages in thread
From: Joe Hershberger @ 2012-08-17 20:49 UTC (permalink / raw)
  To: u-boot

Use variables that define the access type to the env.  This will
simplify validation of access with the ACL.

If deleting a variable that doesn't exist, do nothing

Signed-off-by: Joe Hershberger <joe.hershberger@ni.com>
---
 common/cmd_nvedit.c | 101 +++++++++++++++++++++++++++-------------------------
 tools/env/fw_env.c  |  69 +++++++++++++++++------------------
 2 files changed, 88 insertions(+), 82 deletions(-)

diff --git a/common/cmd_nvedit.c b/common/cmd_nvedit.c
index 76cdd87..0d5b957 100644
--- a/common/cmd_nvedit.c
+++ b/common/cmd_nvedit.c
@@ -207,6 +207,7 @@ int _do_env_set(int flag, int argc, char * const argv[])
 	int   console = -1;
 	char  *name, *value, *s;
 	ENTRY e, *ep;
+	int deleting, creating, overwriting;
 
 	name = argv[1];
 
@@ -224,6 +225,10 @@ int _do_env_set(int flag, int argc, char * const argv[])
 	e.data = NULL;
 	hsearch_r(e, FIND, &ep, &env_htab);
 
+	deleting = (ep && ((argc < 3) || argv[2] == NULL));
+	creating = (!ep && ((argc >= 3) && argv[2] != NULL));
+	overwriting = (ep && ((argc >= 3) && argv[2] != NULL));
+
 	/* Check for console redirection */
 	if (strcmp(name, "stdin") == 0)
 		console = stdin;
@@ -233,7 +238,7 @@ int _do_env_set(int flag, int argc, char * const argv[])
 		console = stderr;
 
 	if (console != -1) {
-		if (argc < 3) {		/* Cannot delete it! */
+		if (deleting) {		/* Cannot delete it! */
 			printf("Can't delete \"%s\"\n", name);
 			return 1;
 		}
@@ -258,7 +263,7 @@ 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 (deleting || overwriting) {		/* variable exists */
 #ifndef CONFIG_ENV_OVERWRITE
 		if (strcmp(name, "serial#") == 0 ||
 		    (strcmp(name, "ethaddr") == 0
@@ -270,6 +275,9 @@ int _do_env_set(int flag, int argc, char * const argv[])
 			return 1;
 		}
 #endif
+	}
+
+	if (creating || overwriting) {
 		/*
 		 * Switch to new baudrate if new baudrate is supported
 		 */
@@ -300,8 +308,7 @@ int _do_env_set(int flag, int argc, char * const argv[])
 		}
 	}
 
-	/* Delete only ? */
-	if (argc < 3 || argv[2] == NULL) {
+	if (deleting) {
 		int rc = hdelete_r(name, &env_htab);
 
 #if defined(CONFIG_SILENT_CONSOLE) && \
@@ -314,59 +321,57 @@ int _do_env_set(int flag, int argc, char * const argv[])
 		return !rc;
 	}
 
+	if (creating || overwriting) {
 #if defined(CONFIG_SILENT_CONSOLE) && \
 	defined(CONFIG_SILENT_CONSOLE_UPDATE_ON_SET)
-	if (strcmp(name, "silent") == 0) {
-		/* silent is added */
-		gd->flags |= GD_FLG_SILENT;
-	}
+		if (strcmp(name, "silent") == 0)
+			/* silent is added */
+			gd->flags |= GD_FLG_SILENT;
 #endif
 
-	/*
-	 * Insert / replace new value
-	 */
-	for (i = 2, len = 0; i < argc; ++i)
-		len += strlen(argv[i]) + 1;
+		for (i = 2, len = 0; i < argc; ++i)
+			len += strlen(argv[i]) + 1;
 
-	value = malloc(len);
-	if (value == NULL) {
-		printf("## Can't malloc %d bytes\n", len);
-		return 1;
-	}
-	for (i = 2, s = value; i < argc; ++i) {
-		char *v = argv[i];
+		value = malloc(len);
+		if (value == NULL) {
+			printf("## Can't malloc %d bytes\n", len);
+			return 1;
+		}
+		for (i = 2, s = value; i < argc; ++i) {
+			char *v = argv[i];
 
-		while ((*s++ = *v++) != '\0')
-			;
-		*(s - 1) = ' ';
-	}
-	if (s != value)
-		*--s = '\0';
-
-	e.key	= name;
-	e.data	= value;
-	hsearch_r(e, ENTER, &ep, &env_htab);
-	free(value);
-	if (!ep) {
-		printf("## Error inserting \"%s\" variable, errno=%d\n",
-			name, errno);
-		return 1;
-	}
+			while ((*s++ = *v++) != '\0')
+				continue;
+			*(s - 1) = ' ';
+		}
+		if (s != value)
+			*--s = '\0';
 
-	/*
-	 * Some variables should be updated when the corresponding
-	 * entry in the environment is changed
-	 */
-	if (strcmp(argv[1], "loadaddr") == 0) {
-		load_addr = simple_strtoul(argv[2], NULL, 16);
-		return 0;
-	}
+		e.key	= name;
+		e.data	= value;
+		hsearch_r(e, ENTER, &ep, &env_htab);
+		free(value);
+		if (!ep) {
+			printf("## Error inserting \"%s\" variable, errno=%d\n",
+				name, errno);
+			return 1;
+		}
+
+		/*
+		 * Some variables should be updated when the corresponding
+		 * entry in the environment is changed
+		 */
+		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;
-	}
+		else if (strcmp(argv[1], "bootfile") == 0) {
+			copy_filename(BootFile, argv[2], sizeof(BootFile));
+			return 0;
+		}
 #endif
+	}
 	return 0;
 }
 
diff --git a/tools/env/fw_env.c b/tools/env/fw_env.c
index 23cf241..a4cd179 100644
--- a/tools/env/fw_env.c
+++ b/tools/env/fw_env.c
@@ -368,6 +368,7 @@ int fw_env_write(char *name, char *value)
 	int len;
 	char *env, *nxt;
 	char *oldval = NULL;
+	int deleting, creating, overwriting;
 
 	/*
 	 * search if variable with this name already exists
@@ -385,10 +386,11 @@ int fw_env_write(char *name, char *value)
 			break;
 	}
 
-	/*
-	 * Delete any existing definition
-	 */
-	if (oldval) {
+	deleting = (oldval && !(value && strlen(value)));
+	creating = (!oldval && (value && strlen(value)));
+	overwriting = (oldval && (value && strlen(value)));
+
+	if (deleting || overwriting) {
 #ifndef CONFIG_ENV_OVERWRITE
 		/*
 		 * Ethernet Address and serial# can be set only once
@@ -419,39 +421,38 @@ int fw_env_write(char *name, char *value)
 		*++env = '\0';
 	}
 
-	/* Delete only ? */
-	if (!value || !strlen(value))
-		return 0;
-
-	/*
-	 * Append new definition@the end
-	 */
-	for (env = environment.data; *env || *(env + 1); ++env);
-	if (env > environment.data)
-		++env;
-	/*
-	 * Overflow when:
-	 * "name" + "=" + "val" +"\0\0"  > CUR_ENVSIZE - (env-environment)
-	 */
-	len = strlen (name) + 2;
-	/* add '=' for first arg, ' ' for all others */
-	len += strlen(value) + 1;
+	if (creating || overwriting) {
+		/*
+		 * Append new definition at the end
+		 */
+		for (env = environment.data; *env || *(env + 1); ++env)
+			continue;
+		if (env > environment.data)
+			++env;
+		/*
+		 * Overflow when:
+		 * "name" + "=" + "val" +"\0\0"  > CUR_ENVSIZE - (env)
+		 */
+		len = strlen(name) + 2;
+		/* add '=' for first arg, ' ' for all others */
+		len += strlen(value) + 1;
 
-	if (len > (&environment.data[ENV_SIZE] - env)) {
-		fprintf (stderr,
-			"Error: environment overflow, \"%s\" deleted\n",
-			name);
-		return -1;
-	}
+		if (len > (&environment.data[ENV_SIZE] - env)) {
+			fprintf(stderr,
+				"Error: environment overflow, \"%s\" deleted\n",
+				name);
+			return -1;
+		}
 
-	while ((*env = *name++) != '\0')
-		env++;
-	*env = '=';
-	while ((*++env = *value++) != '\0')
-		;
+		while ((*env = *name++) != '\0')
+			env++;
+		*env = '=';
+		while ((*++env = *value++) != '\0')
+			continue;
 
-	/* end is marked with double '\0' */
-	*++env = '\0';
+		/* end is marked with double '\0' */
+		*++env = '\0';
+	}
 
 	return 0;
 }
-- 
1.7.11.5

^ permalink raw reply related	[flat|nested] 124+ messages in thread

* [U-Boot] [PATCH 10/12] env: acl: Add environment variable access control list
  2012-08-17 20:49                             ` [U-Boot] [PATCH 0/12] Add environment type checking and access control Joe Hershberger
                                                 ` (8 preceding siblings ...)
  2012-08-17 20:49                               ` [U-Boot] [PATCH 09/12] env: Clarify the cases for env set Joe Hershberger
@ 2012-08-17 20:49                               ` Joe Hershberger
  2012-08-23  3:43                                 ` Mike Frysinger
  2012-09-13 20:13                                 ` Wolfgang Denk
  2012-08-17 20:49                               ` [U-Boot] [PATCH 11/12] env: acl: Add support for access control to env ACL Joe Hershberger
                                                 ` (2 subsequent siblings)
  12 siblings, 2 replies; 124+ messages in thread
From: Joe Hershberger @ 2012-08-17 20:49 UTC (permalink / raw)
  To: u-boot

Currently just validates variable types as decimal, hexidecimal,
boolean, ip address, and mac address.  Call
env_acl_validate_setenv_params() from setenv() in both cmd_nvedit.c
and fw_env.c.

If the entry is not found in the env ACL, then look in the static one.
This allows the env to override the static definitions, but prevents
the need to have every definition in the environment distracting you.

Move min macro from fw_env.c to fw_env.h... it is needed by env_acl.c
when building for Linux.

Need to build in _ctype for isdigit for Linux.

Signed-off-by: Joe Hershberger <joe.hershberger@ni.com>
---
 README                |  31 ++++++
 common/Makefile       |   1 +
 common/cmd_nvedit.c   |   8 ++
 common/env_acl.c      | 270 ++++++++++++++++++++++++++++++++++++++++++++++++++
 common/env_common.c   |   3 +
 common/env_embedded.c |   3 +
 include/env_acl.h     |  49 +++++++++
 tools/env/Makefile    |   2 +
 tools/env/fw_env.c    |  25 +++--
 tools/env/fw_env.h    |   6 ++
 10 files changed, 392 insertions(+), 6 deletions(-)
 create mode 100644 common/env_acl.c
 create mode 100644 include/env_acl.h

diff --git a/README b/README
index fb9d904..2e34bcd 100644
--- a/README
+++ b/README
@@ -2908,6 +2908,37 @@ Configuration Settings:
 	cases. This setting can be used to tune behaviour; see
 	lib/hashtable.c for details.
 
+- CONFIG_ENV_ACL
+	Enable validation of the values given to enviroment variables when
+	calling env set.  Variables can be restricted to only decimal,
+	hexadecimal, or boolean.  If CONFIG_CMD_NET is also defined,
+	the variables can also be restricted to IP address or MAC address.
+
+	The format of the list is:
+		type_attribute = [s|d|x|b|i|m]
+		attributes = type_attribute
+		entry = variable_name[:attributes]
+		list = entry[,list]
+
+	The type attributes are:
+		s - String (default)
+		d - Decimal
+		x - Hexadecimal
+		b - Boolean
+		i - IP address
+		m - MAC address
+
+	- CONFIG_ENV_ACL_DEFAULT
+		Define this to a list (string) to define the "acl" envirnoment
+		variable in the default or embedded environment.
+
+	- CONFIG_ENV_ACL_STATIC
+		Define this to a list (string) to define validation that
+		should be done if an entry is not found in the "acl"
+		environment variable.  To override a setting in the static
+		list, simply add an entry for the same variable name to the
+		"acl" variable.
+
 The following definitions that deal with the placement and management
 of environment data (variable area); in general, we support the
 following configurations:
diff --git a/common/Makefile b/common/Makefile
index 3d62775..64522e1 100644
--- a/common/Makefile
+++ b/common/Makefile
@@ -44,6 +44,7 @@ COBJS-y += cmd_version.o
 
 # environment
 COBJS-y += env_common.o
+COBJS-$(CONFIG_ENV_ACL) += env_acl.o
 COBJS-$(CONFIG_ENV_IS_IN_DATAFLASH) += env_dataflash.o
 COBJS-$(CONFIG_ENV_IS_IN_EEPROM) += env_eeprom.o
 XCOBJS-$(CONFIG_ENV_IS_EMBEDDED) += env_embedded.o
diff --git a/common/cmd_nvedit.c b/common/cmd_nvedit.c
index 0d5b957..b761b2c 100644
--- a/common/cmd_nvedit.c
+++ b/common/cmd_nvedit.c
@@ -43,6 +43,9 @@
 #include <common.h>
 #include <command.h>
 #include <environment.h>
+#if defined(CONFIG_ENV_ACL)
+#include <env_acl.h>
+#endif
 #include <search.h>
 #include <errno.h>
 #include <malloc.h>
@@ -217,6 +220,11 @@ int _do_env_set(int flag, int argc, char * const argv[])
 		return 1;
 	}
 
+#ifdef CONFIG_ENV_ACL
+	if (env_acl_validate_env_set_params(argc, argv) < 0)
+		return 1;
+#endif
+
 	env_id++;
 	/*
 	 * search if variable with this name already exists
diff --git a/common/env_acl.c b/common/env_acl.c
new file mode 100644
index 0000000..7c86243
--- /dev/null
+++ b/common/env_acl.c
@@ -0,0 +1,270 @@
+/*
+ * (C) Copyright 2010
+ * 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
+ */
+
+#include <linux/string.h>
+#include <linux/ctype.h>
+
+#ifdef USE_HOSTCC /* Eliminate "ANSI does not permit..." warnings */
+#include <stdint.h>
+#include <stdio.h>
+#include "fw_env.h"
+#define getenv fw_getenv
+#else
+#include <common.h>
+#endif
+
+#include <env_acl.h>
+
+#ifdef CONFIG_CMD_NET
+#define ENV_ACL_NET_TYPE_REPS "im"
+#else
+#define ENV_ACL_NET_TYPE_REPS ""
+#endif
+
+#ifndef CONFIG_ENV_ACL_STATIC
+#define CONFIG_ENV_ACL_STATIC ""
+#endif
+
+static const char env_acl_static[] = CONFIG_ENV_ACL_STATIC "\0";
+static const char env_acl_type_rep[] = "sdxb" ENV_ACL_NET_TYPE_REPS;
+
+static int _env_acl_lookup_r(const char *name, char *attributes, int static_acl)
+{
+	const char *acl;
+	const char *entry = NULL;
+
+	if (static_acl)
+		acl = &env_acl_static[0];
+	else
+		acl = getenv(ENV_ACL_LIST_VAR_NAME);
+
+	if (!attributes)
+		/* bad parameter */
+		return -1;
+	if (!acl)
+		/* list not found */
+		return 1;
+
+	entry = strstr(acl, name);
+	while (entry != NULL) {
+		if ((entry == acl || *(entry - 1) == ENV_ACL_LIST_DELIM ||
+		    *(entry - 1) == ' ') &&
+		    (*(entry + strlen(name)) == ENV_ACL_ATTR_SEP ||
+		     *(entry + strlen(name)) == ENV_ACL_LIST_DELIM ||
+		     *(entry + strlen(name)) == '\0' ||
+		     *(entry + strlen(name)) == ' '))
+			break;
+		entry++;
+		entry = strstr(entry, name);
+	}
+	if (entry != NULL) {
+		int len;
+
+		/* skip the name */
+		entry += strlen(name);
+		/* skip spaces */
+		while (*entry == ' ')
+			entry++;
+		if (*entry != ENV_ACL_ATTR_SEP)
+			len = 0;
+		else {
+			const char *delim;
+			const char delims[2] = {ENV_ACL_LIST_DELIM, ' '};
+
+			/* skip the attr sep */
+			entry += 1;
+			/* skip spaces */
+			while (*entry == ' ')
+				entry++;
+
+			delim = strpbrk(entry, delims);
+			if (delim == NULL)
+				len = strlen(entry);
+			else
+				len = delim - entry;
+			len = min(len, ENV_ACL_ATTR_MAX_LEN);
+			memcpy(attributes, entry, len);
+		}
+		attributes[len] = '\0';
+
+		/* success */
+		return 0;
+	}
+	/* not found in list */
+	return 2;
+}
+
+static int env_acl_lookup_r(const char *name, char *attributes)
+{
+	int ret_val;
+	/* try the env first */
+	ret_val = _env_acl_lookup_r(name, attributes, 0);
+	if (ret_val != 0) {
+		/* if not found in the env, look in the static list */
+		ret_val = _env_acl_lookup_r(name, attributes, 1);
+	}
+	return ret_val;
+}
+
+enum env_acl_var_type env_acl_get_type(const char *name)
+{
+	char *type;
+	char attr[ENV_ACL_ATTR_MAX_LEN + 1];
+
+	if (env_acl_lookup_r(name, attr))
+		return ENV_ACL_VAR_TYPE_STRING;
+
+	if (strlen(attr) <= ENV_ACL_TYPE_LOC)
+		return ENV_ACL_VAR_TYPE_STRING;
+
+	type = strchr(env_acl_type_rep, attr[ENV_ACL_TYPE_LOC]);
+
+	if (type != NULL)
+		return (enum env_acl_var_type)(type - &env_acl_type_rep[0]);
+
+	printf("## Warning: Unknown environment variable type '%c'\n",
+		attr[ENV_ACL_TYPE_LOC]);
+	return ENV_ACL_VAR_TYPE_STRING;
+}
+
+static inline int is_hex_prefix(const char *value)
+{
+	return value[0] == '0' && (value[1] == 'x' || value[1] == 'X');
+}
+
+static void skip_num(int hex, const char *value, const char **end,
+	int max_digits)
+{
+	int i;
+
+	if (hex && is_hex_prefix(value))
+		value += 2;
+
+	for (i = max_digits; i != 0; i--) {
+		if (hex && !isxdigit(*value))
+			break;
+		if (!hex && !isdigit(*value))
+			break;
+		value++;
+	}
+	if (end != NULL)
+		*end = value;
+}
+
+static int _env_acl_validate_type(const char *value, enum env_acl_var_type type)
+{
+	const char *end;
+	const char *cur;
+	int i;
+
+	switch (type) {
+	case ENV_ACL_VAR_TYPE_STRING:
+		break;
+	case ENV_ACL_VAR_TYPE_DECIMAL:
+		skip_num(0, value, &end, -1);
+		if (*end != '\0')
+			return -1;
+		break;
+	case ENV_ACL_VAR_TYPE_HEX:
+		skip_num(1, value, &end, -1);
+		if (*end != '\0')
+			return -1;
+		if (value + 2 == end && is_hex_prefix(value))
+			return -1;
+		break;
+	case ENV_ACL_VAR_TYPE_BOOL:
+		if (value[0] != '0' && value[0] != '1')
+			return -1;
+		if (value[1] != '\0')
+			return -1;
+		break;
+#ifdef CONFIG_CMD_NET
+	case ENV_ACL_VAR_TYPE_IPADDR:
+		cur = value;
+		for (i = 0; i < 4; i++) {
+			skip_num(0, cur, &end, 3);
+			if (cur == end)
+				return -1;
+			if (i != 3 && *end != '.')
+				return -1;
+			if (i == 3 && *end != '\0')
+				return -1;
+			cur = end + 1;
+		}
+		break;
+	case ENV_ACL_VAR_TYPE_MACADDR:
+		cur = value;
+		for (i = 0; i < 6; i++) {
+			skip_num(1, cur, &end, 2);
+			if (cur == end)
+				return -1;
+			if (cur + 2 == end && is_hex_prefix(cur))
+				return -1;
+			if (i != 5 && *end != ':')
+				return -1;
+			if (i == 5 && *end != '\0')
+				return -1;
+			cur = end + 1;
+		}
+		break;
+#endif
+	}
+
+	/* OK */
+	return 0;
+}
+
+int env_acl_validate_type(const char *name, const char *value)
+{
+	enum env_acl_var_type type = env_acl_get_type(name);
+
+	if (value == NULL)
+		return 0;
+	if (_env_acl_validate_type(value, type) < 0) {
+		printf("## Error: acl type check failure for "
+			"\"%s\" <= \"%s\" (type: %c)\n",
+			name, value, env_acl_type_rep[type]);
+		return -1;
+	}
+	return 0;
+}
+
+int env_acl_validate_env_set_params(int argc, char * const argv[])
+{
+	if ((argc >= 3) && argv[2] != NULL) {
+		enum env_acl_var_type type = env_acl_get_type(argv[1]);
+
+		/*
+		 * we don't currently check types that need more than
+		 * one argument
+		 */
+		if (type != ENV_ACL_VAR_TYPE_STRING && argc > 3) {
+			printf("## Error: too many parameters for setting "
+				"\"%s\"\n", argv[1]);
+			return -1;
+		}
+		return env_acl_validate_type(argv[1], argv[2]);
+	}
+	/* ok */
+	return 0;
+}
diff --git a/common/env_common.c b/common/env_common.c
index e58971d..c32c846 100644
--- a/common/env_common.c
+++ b/common/env_common.c
@@ -127,6 +127,9 @@ const uchar default_environment[] = {
 	"soc="		CONFIG_SYS_SOC			"\0"
 #endif
 #endif
+#ifdef	CONFIG_ENV_ACL_DEFAULT
+	"acl="		CONFIG_ENV_ACL_DEFAULT		"\0"
+#endif
 #ifdef	CONFIG_EXTRA_ENV_SETTINGS
 	CONFIG_EXTRA_ENV_SETTINGS
 #endif
diff --git a/common/env_embedded.c b/common/env_embedded.c
index 3872878..949fb95 100644
--- a/common/env_embedded.c
+++ b/common/env_embedded.c
@@ -190,6 +190,9 @@ env_t environment __PPCENV__ = {
 	"soc="		CONFIG_SYS_SOC			"\0"
 #endif
 #endif
+#ifdef	CONFIG_ENV_ACL_DEFAULT
+	"acl="		CONFIG_ENV_ACL_DEFAULT		"\0"
+#endif
 #ifdef	CONFIG_EXTRA_ENV_SETTINGS
 	CONFIG_EXTRA_ENV_SETTINGS
 #endif
diff --git a/include/env_acl.h b/include/env_acl.h
new file mode 100644
index 0000000..9b0a199
--- /dev/null
+++ b/include/env_acl.h
@@ -0,0 +1,49 @@
+/*
+ * (C) Copyright 2010
+ * Joe Hershberger, National Instruments, joe.hershberger at 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
+ */
+
+#ifndef __ENV_ACL_H__
+#define __ENV_ACL_H__
+
+enum env_acl_var_type {
+	ENV_ACL_VAR_TYPE_STRING,
+	ENV_ACL_VAR_TYPE_DECIMAL,
+	ENV_ACL_VAR_TYPE_HEX,
+	ENV_ACL_VAR_TYPE_BOOL,
+#ifdef CONFIG_CMD_NET
+	ENV_ACL_VAR_TYPE_IPADDR,
+	ENV_ACL_VAR_TYPE_MACADDR,
+#endif
+};
+
+#define ENV_ACL_LIST_DELIM	','
+#define ENV_ACL_ATTR_SEP	':'
+#define ENV_ACL_LIST_VAR_NAME	"acl"
+#define ENV_ACL_ATTR_MAX_LEN	2
+#define ENV_ACL_TYPE_LOC	0
+
+enum env_acl_var_type env_acl_get_type(const char *name);
+int env_acl_validate_type(const char *name, const char *value);
+int env_acl_validate_env_set_params(int argc, char * const argv[]);
+
+
+#endif /* __ENV_ACL_H__ */
diff --git a/tools/env/Makefile b/tools/env/Makefile
index ab73c8c..82b49a0 100644
--- a/tools/env/Makefile
+++ b/tools/env/Makefile
@@ -24,12 +24,14 @@
 include $(TOPDIR)/config.mk
 
 HOSTSRCS := $(SRCTREE)/lib/crc32.c  fw_env.c  fw_env_main.c
+HOSTSRCS += $(SRCTREE)/lib/ctype.c $(SRCTREE)/common/env_acl.c
 HEADERS	:= fw_env.h $(OBJTREE)/include/config.h
 
 # Compile for a hosted environment on the target
 HOSTCPPFLAGS  = -idirafter $(SRCTREE)/include \
 		-idirafter $(OBJTREE)/include2 \
 		-idirafter $(OBJTREE)/include \
+		-idirafter $(SRCTREE)/tools/env \
 		-DUSE_HOSTCC \
 		-DTEXT_BASE=$(TEXT_BASE)
 
diff --git a/tools/env/fw_env.c b/tools/env/fw_env.c
index a4cd179..f7807b5 100644
--- a/tools/env/fw_env.c
+++ b/tools/env/fw_env.c
@@ -45,16 +45,14 @@
 
 #include "fw_env.h"
 
+#if defined(CONFIG_ENV_ACL)
+#include <env_acl.h>
+#endif
+
 #define MAX_BYTES_PER_READ 0x20
 
 #define WHITESPACE(c) ((c == '\t') || (c == ' '))
 
-#define min(x, y) ({				\
-	typeof(x) _min1 = (x);			\
-	typeof(y) _min2 = (y);			\
-	(void) (&_min1 == &_min2);		\
-	_min1 < _min2 ? _min1 : _min2; })
-
 struct envdev_s {
 	char devname[16];		/* Device name */
 	ulong devoff;			/* Device offset */
@@ -203,6 +201,9 @@ static char default_environment[] = {
 #if defined(CONFIG_PCI_BOOTDELAY) && (CONFIG_PCI_BOOTDELAY > 0)
 	"pcidelay=" MK_STR (CONFIG_PCI_BOOTDELAY) "\0"
 #endif
+#ifdef	CONFIG_ENV_ACL_DEFAULT
+	"acl=" CONFIG_ENV_ACL_DEFAULT "\0"
+#endif
 #ifdef  CONFIG_EXTRA_ENV_SETTINGS
 	CONFIG_EXTRA_ENV_SETTINGS
 #endif
@@ -484,6 +485,11 @@ int fw_setenv(int argc, char *argv[])
 
 	name = argv[1];
 
+#if defined(CONFIG_ENV_ACL)
+	if (env_acl_validate_env_set_params(argc, argv) < 0)
+		return 1;
+#endif
+
 	len = 0;
 	for (i = 2; i < argc; ++i)
 		len += strlen(argv[i]) + 1;
@@ -611,6 +617,13 @@ int fw_parse_script(char *fname)
 			name, val ? val : " removed");
 #endif
 
+#if defined(CONFIG_ENV_ACL)
+		if (env_acl_validate_type(name, val) < 0) {
+			ret = -1;
+			break;
+		}
+#endif
+
 		/*
 		 * If there is an error setting a variable,
 		 * try to save the environment and returns an error
diff --git a/tools/env/fw_env.h b/tools/env/fw_env.h
index a1a6807..eca168a 100644
--- a/tools/env/fw_env.h
+++ b/tools/env/fw_env.h
@@ -77,3 +77,9 @@ extern int fw_env_write(char *name, char *value);
 extern int fw_env_close(void);
 
 extern unsigned	long  crc32	 (unsigned long, const unsigned char *, unsigned);
+
+#define min(x, y) ({				\
+	typeof(x) _min1 = (x);			\
+	typeof(y) _min2 = (y);			\
+	(void) (&_min1 == &_min2);		\
+	_min1 < _min2 ? _min1 : _min2; })
-- 
1.7.11.5

^ permalink raw reply related	[flat|nested] 124+ messages in thread

* [U-Boot] [PATCH 11/12] env: acl: Add support for access control to env ACL
  2012-08-17 20:49                             ` [U-Boot] [PATCH 0/12] Add environment type checking and access control Joe Hershberger
                                                 ` (9 preceding siblings ...)
  2012-08-17 20:49                               ` [U-Boot] [PATCH 10/12] env: acl: Add environment variable access control list Joe Hershberger
@ 2012-08-17 20:49                               ` Joe Hershberger
  2012-08-17 20:49                               ` [U-Boot] [PATCH 12/12] env: cosmetic: Consilidate the default env definition Joe Hershberger
  2012-10-03 19:38                               ` [U-Boot] [PATCH v2 0/5] Cleanup fw_*env and a few common env Joe Hershberger
  12 siblings, 0 replies; 124+ messages in thread
From: Joe Hershberger @ 2012-08-17 20:49 UTC (permalink / raw)
  To: u-boot

Add support for read-only and write-once.

Signed-off-by: Joe Hershberger <joe.hershberger@ni.com>
---
 README              | 13 +++++++++++-
 common/cmd_nvedit.c | 51 ++++++++++++++++++++++++++++++++++++++++++++
 common/env_acl.c    | 38 +++++++++++++++++++++++++++++++++
 include/env_acl.h   | 14 ++++++++++++
 tools/env/fw_env.c  | 61 +++++++++++++++++++++++++++++++++++++++++++++++++++++
 5 files changed, 176 insertions(+), 1 deletion(-)

diff --git a/README b/README
index 2e34bcd..fa665f0 100644
--- a/README
+++ b/README
@@ -2094,6 +2094,11 @@ The following options need to be configured:
 		serial# is unaffected by this, i. e. it remains
 		read-only.]
 
+		The same can be accomplished in a more flexible way
+		for any variable by defining CONFIG_ENV_ACL and
+		specifying the type of access to allow to each
+		variable.
+
 - Protected RAM:
 		CONFIG_PRAM
 
@@ -2916,7 +2921,8 @@ Configuration Settings:
 
 	The format of the list is:
 		type_attribute = [s|d|x|b|i|m]
-		attributes = type_attribute
+		access_atribute = [a|r|o]
+		attributes = type_attribute[access_atribute]
 		entry = variable_name[:attributes]
 		list = entry[,list]
 
@@ -2928,6 +2934,11 @@ Configuration Settings:
 		i - IP address
 		m - MAC address
 
+	The access attributes are:
+		a - Any (default)
+		r - Read-only
+		o - Write-once (change default)
+
 	- CONFIG_ENV_ACL_DEFAULT
 		Define this to a list (string) to define the "acl" envirnoment
 		variable in the default or embedded environment.
diff --git a/common/cmd_nvedit.c b/common/cmd_nvedit.c
index b761b2c..13b6e08 100644
--- a/common/cmd_nvedit.c
+++ b/common/cmd_nvedit.c
@@ -200,6 +200,23 @@ static int do_env_grep(cmd_tbl_t *cmdtp, int flag,
 }
 #endif
 
+#ifdef CONFIG_ENV_ACL
+/*
+ * Look up the variable from the default environment
+ */
+static char *getdefenv(const char *name)
+{
+	char *ret_val;
+	unsigned long really_valid = gd->env_valid;
+
+	/* Pretend that the image is bad. */
+	gd->env_valid = 0;
+	ret_val = getenv(name);
+	gd->env_valid = really_valid;
+	return ret_val;
+}
+#endif
+
 /*
  * Set a new environment variable,
  * or replace or delete an existing one.
@@ -237,6 +254,40 @@ int _do_env_set(int flag, int argc, char * const argv[])
 	creating = (!ep && ((argc >= 3) && argv[2] != NULL));
 	overwriting = (ep && ((argc >= 3) && argv[2] != NULL));
 
+#ifdef CONFIG_ENV_ACL
+	/* check for permission */
+	if (deleting) {
+		if (env_acl_validate_access(name, ENV_ACL_PREVENT_DELETE)) {
+			printf("## Error: Can't delete \"%s\"\n", name);
+			return 1;
+		}
+	} else if (overwriting) {
+		if (env_acl_validate_access(name, ENV_ACL_PREVENT_OVERWR)) {
+			printf("## Error: Can't overwrite \"%s\"\n", name);
+			return 1;
+		} else if (env_acl_validate_access(name,
+		    ENV_ACL_PREVENT_NONDEF_OVERWR)) {
+			const char *defval = getdefenv(name);
+
+			if (defval == NULL)
+				defval = "";
+			if (strcmp(ep->data, defval)
+			    != 0) {
+				printf("## Error: Can't overwrite \"%s\"\n",
+					name);
+				return 1;
+			}
+		}
+	} else if (creating) {
+		if (env_acl_validate_access(name, ENV_ACL_PREVENT_CREATE)) {
+			printf("## Error: Can't create \"%s\"\n", name);
+			return 1;
+		}
+	} else
+		/* Nothing to do */
+		return 0;
+#endif
+
 	/* Check for console redirection */
 	if (strcmp(name, "stdin") == 0)
 		console = stdin;
diff --git a/common/env_acl.c b/common/env_acl.c
index 7c86243..1a75e09 100644
--- a/common/env_acl.c
+++ b/common/env_acl.c
@@ -47,6 +47,12 @@
 
 static const char env_acl_static[] = CONFIG_ENV_ACL_STATIC "\0";
 static const char env_acl_type_rep[] = "sdxb" ENV_ACL_NET_TYPE_REPS;
+static const char env_acl_access_rep[] = "aro";
+static const char env_acl_access_mask[] = {
+	0,
+	ENV_ACL_PREVENT_DELETE | ENV_ACL_PREVENT_CREATE |
+		ENV_ACL_PREVENT_OVERWR,
+	ENV_ACL_PREVENT_DELETE | ENV_ACL_PREVENT_NONDEF_OVERWR};
 
 static int _env_acl_lookup_r(const char *name, char *attributes, int static_acl)
 {
@@ -147,6 +153,27 @@ enum env_acl_var_type env_acl_get_type(const char *name)
 	return ENV_ACL_VAR_TYPE_STRING;
 }
 
+enum env_acl_var_access env_acl_get_access(const char *name)
+{
+	char *access;
+	char attr[ENV_ACL_ATTR_MAX_LEN + 1];
+	if (env_acl_lookup_r(name, attr))
+		return ENV_ACL_VAR_ACCESS_ANY;
+
+	if (strlen(attr) <= ENV_ACL_ACCESS_LOC)
+		return ENV_ACL_VAR_ACCESS_ANY;
+
+	access = strchr(env_acl_access_rep, attr[ENV_ACL_ACCESS_LOC]);
+
+	if (access != NULL)
+		return (enum env_acl_var_access)
+			(access - &env_acl_access_rep[0]);
+
+	printf("## Warning: Unknown environment variable access method '%c'\n",
+		attr[ENV_ACL_ACCESS_LOC]);
+	return ENV_ACL_VAR_ACCESS_ANY;
+}
+
 static inline int is_hex_prefix(const char *value)
 {
 	return value[0] == '0' && (value[1] == 'x' || value[1] == 'X');
@@ -249,6 +276,17 @@ int env_acl_validate_type(const char *name, const char *value)
 	return 0;
 }
 
+int env_acl_validate_access(const char *name, int check_mask)
+{
+	enum env_acl_var_access access;
+	int access_mask;
+
+	access = env_acl_get_access(name);
+	access_mask = env_acl_access_mask[access];
+
+	return (check_mask & access_mask) != 0;
+}
+
 int env_acl_validate_env_set_params(int argc, char * const argv[])
 {
 	if ((argc >= 3) && argv[2] != NULL) {
diff --git a/include/env_acl.h b/include/env_acl.h
index 9b0a199..09618f9 100644
--- a/include/env_acl.h
+++ b/include/env_acl.h
@@ -35,14 +35,28 @@ enum env_acl_var_type {
 #endif
 };
 
+enum env_acl_var_access {
+	ENV_ACL_VAR_ACCESS_ANY,
+	ENV_ACL_VAR_ACCESS_READ,
+	ENV_ACL_VAR_ACCESS_SET_ONCE,
+};
+
+#define ENV_ACL_PREVENT_DELETE		0x01
+#define ENV_ACL_PREVENT_CREATE		0x02
+#define ENV_ACL_PREVENT_OVERWR		0x04
+#define ENV_ACL_PREVENT_NONDEF_OVERWR	0x08
+
 #define ENV_ACL_LIST_DELIM	','
 #define ENV_ACL_ATTR_SEP	':'
 #define ENV_ACL_LIST_VAR_NAME	"acl"
 #define ENV_ACL_ATTR_MAX_LEN	2
 #define ENV_ACL_TYPE_LOC	0
+#define ENV_ACL_ACCESS_LOC	1
 
 enum env_acl_var_type env_acl_get_type(const char *name);
+enum env_acl_var_access env_acl_get_access(const char *name);
 int env_acl_validate_type(const char *name, const char *value);
+int env_acl_validate_access(const char *name, int check_mask);
 int env_acl_validate_env_set_params(int argc, char * const argv[]);
 
 
diff --git a/tools/env/fw_env.c b/tools/env/fw_env.c
index f7807b5..60ff06c 100644
--- a/tools/env/fw_env.c
+++ b/tools/env/fw_env.c
@@ -268,6 +268,34 @@ char *fw_getenv (char *name)
 	return NULL;
 }
 
+#ifdef CONFIG_ENV_ACL
+/*
+ * Search the default environment for a variable.
+ * Return the value, if found, or NULL, if not found.
+ */
+char *fw_getdefenv(char *name)
+{
+	char *env, *nxt;
+
+	for (env = default_environment; *env; env = nxt + 1) {
+		char *val;
+
+		for (nxt = env; *nxt; ++nxt) {
+			if (nxt >= &default_environment[ENV_SIZE]) {
+				fprintf(stderr, "## Error: "
+					"default environment not terminated\n");
+				return NULL;
+			}
+		}
+		val = envmatch(name, env);
+		if (!val)
+			continue;
+		return val;
+	}
+	return NULL;
+}
+#endif
+
 /*
  * Print the current definition of one, or more, or all
  * environment variables
@@ -391,6 +419,39 @@ int fw_env_write(char *name, char *value)
 	creating = (!oldval && (value && strlen(value)));
 	overwriting = (oldval && (value && strlen(value)));
 
+#ifdef CONFIG_ENV_ACL
+	/* check for permission */
+	if (deleting) {
+		if (env_acl_validate_access(name, ENV_ACL_PREVENT_DELETE)) {
+			printf("Can't delete \"%s\"\n", name);
+			return 1;
+		}
+	} else if (overwriting) {
+		if (env_acl_validate_access(name, ENV_ACL_PREVENT_OVERWR)) {
+			printf("Can't overwrite \"%s\"\n", name);
+			return 1;
+		} else if (env_acl_validate_access(name,
+		    ENV_ACL_PREVENT_NONDEF_OVERWR)) {
+			const char *defval = fw_getdefenv(name);
+
+			if (defval == NULL)
+				defval = "";
+			if (strcmp(oldval, defval)
+			    != 0) {
+				printf("Can't overwrite \"%s\"\n", name);
+				return 1;
+			}
+		}
+	} else if (creating) {
+		if (env_acl_validate_access(name, ENV_ACL_PREVENT_CREATE)) {
+			printf("Can't create \"%s\"\n", name);
+			return 1;
+		}
+	} else
+		/* Nothing to do */
+		return 0;
+#endif
+
 	if (deleting || overwriting) {
 #ifndef CONFIG_ENV_OVERWRITE
 		/*
-- 
1.7.11.5

^ permalink raw reply related	[flat|nested] 124+ messages in thread

* [U-Boot] [PATCH 12/12] env: cosmetic: Consilidate the default env definition
  2012-08-17 20:49                             ` [U-Boot] [PATCH 0/12] Add environment type checking and access control Joe Hershberger
                                                 ` (10 preceding siblings ...)
  2012-08-17 20:49                               ` [U-Boot] [PATCH 11/12] env: acl: Add support for access control to env ACL Joe Hershberger
@ 2012-08-17 20:49                               ` Joe Hershberger
  2012-08-23  3:44                                 ` Mike Frysinger
  2012-10-03 19:38                               ` [U-Boot] [PATCH v2 0/5] Cleanup fw_*env and a few common env Joe Hershberger
  12 siblings, 1 reply; 124+ messages in thread
From: Joe Hershberger @ 2012-08-17 20:49 UTC (permalink / raw)
  To: u-boot

There used to be a huge structure duplicated 3 times in the source.

Signed-off-by: Joe Hershberger <joe.hershberger@ni.com>
---
 common/env_common.c   |  99 +----------------------------------
 common/env_embedded.c | 114 ++--------------------------------------
 include/env_default.h | 142 ++++++++++++++++++++++++++++++++++++++++++++++++++
 tools/env/fw_env.c    |  93 +--------------------------------
 4 files changed, 148 insertions(+), 300 deletions(-)
 create mode 100644 include/env_default.h

diff --git a/common/env_common.c b/common/env_common.c
index c32c846..f6f2a77 100644
--- a/common/env_common.c
+++ b/common/env_common.c
@@ -37,104 +37,7 @@ DECLARE_GLOBAL_DATA_PTR;
 /************************************************************************
  * Default settings to be used when no valid environment is found
  */
-#define XMK_STR(x)	#x
-#define MK_STR(x)	XMK_STR(x)
-
-const uchar default_environment[] = {
-#ifdef	CONFIG_BOOTARGS
-	"bootargs="	CONFIG_BOOTARGS			"\0"
-#endif
-#ifdef	CONFIG_BOOTCOMMAND
-	"bootcmd="	CONFIG_BOOTCOMMAND		"\0"
-#endif
-#ifdef	CONFIG_RAMBOOTCOMMAND
-	"ramboot="	CONFIG_RAMBOOTCOMMAND		"\0"
-#endif
-#ifdef	CONFIG_NFSBOOTCOMMAND
-	"nfsboot="	CONFIG_NFSBOOTCOMMAND		"\0"
-#endif
-#if defined(CONFIG_BOOTDELAY) && (CONFIG_BOOTDELAY >= 0)
-	"bootdelay="	MK_STR(CONFIG_BOOTDELAY)	"\0"
-#endif
-#if defined(CONFIG_BAUDRATE) && (CONFIG_BAUDRATE >= 0)
-	"baudrate="	MK_STR(CONFIG_BAUDRATE)		"\0"
-#endif
-#ifdef	CONFIG_LOADS_ECHO
-	"loads_echo="	MK_STR(CONFIG_LOADS_ECHO)	"\0"
-#endif
-#ifdef	CONFIG_ETHADDR
-	"ethaddr="	MK_STR(CONFIG_ETHADDR)		"\0"
-#endif
-#ifdef	CONFIG_ETH1ADDR
-	"eth1addr="	MK_STR(CONFIG_ETH1ADDR)		"\0"
-#endif
-#ifdef	CONFIG_ETH2ADDR
-	"eth2addr="	MK_STR(CONFIG_ETH2ADDR)		"\0"
-#endif
-#ifdef	CONFIG_ETH3ADDR
-	"eth3addr="	MK_STR(CONFIG_ETH3ADDR)		"\0"
-#endif
-#ifdef	CONFIG_ETH4ADDR
-	"eth4addr="	MK_STR(CONFIG_ETH4ADDR)		"\0"
-#endif
-#ifdef	CONFIG_ETH5ADDR
-	"eth5addr="	MK_STR(CONFIG_ETH5ADDR)		"\0"
-#endif
-#ifdef	CONFIG_IPADDR
-	"ipaddr="	MK_STR(CONFIG_IPADDR)		"\0"
-#endif
-#ifdef	CONFIG_SERVERIP
-	"serverip="	MK_STR(CONFIG_SERVERIP)		"\0"
-#endif
-#ifdef	CONFIG_SYS_AUTOLOAD
-	"autoload="	CONFIG_SYS_AUTOLOAD		"\0"
-#endif
-#ifdef	CONFIG_PREBOOT
-	"preboot="	CONFIG_PREBOOT			"\0"
-#endif
-#ifdef	CONFIG_ROOTPATH
-	"rootpath="	CONFIG_ROOTPATH			"\0"
-#endif
-#ifdef	CONFIG_GATEWAYIP
-	"gatewayip="	MK_STR(CONFIG_GATEWAYIP)	"\0"
-#endif
-#ifdef	CONFIG_NETMASK
-	"netmask="	MK_STR(CONFIG_NETMASK)		"\0"
-#endif
-#ifdef	CONFIG_HOSTNAME
-	"hostname="	MK_STR(CONFIG_HOSTNAME)		"\0"
-#endif
-#ifdef	CONFIG_BOOTFILE
-	"bootfile="	CONFIG_BOOTFILE			"\0"
-#endif
-#ifdef	CONFIG_LOADADDR
-	"loadaddr="	MK_STR(CONFIG_LOADADDR)		"\0"
-#endif
-#ifdef	CONFIG_CLOCKS_IN_MHZ
-	"clocks_in_mhz=1\0"
-#endif
-#if defined(CONFIG_PCI_BOOTDELAY) && (CONFIG_PCI_BOOTDELAY > 0)
-	"pcidelay="	MK_STR(CONFIG_PCI_BOOTDELAY)	"\0"
-#endif
-#ifdef	CONFIG_ENV_VARS_UBOOT_CONFIG
-	"arch="		CONFIG_SYS_ARCH			"\0"
-	"cpu="		CONFIG_SYS_CPU			"\0"
-	"board="	CONFIG_SYS_BOARD		"\0"
-#ifdef CONFIG_SYS_VENDOR
-	"vendor="	CONFIG_SYS_VENDOR		"\0"
-#endif
-#ifdef CONFIG_SYS_SOC
-	"soc="		CONFIG_SYS_SOC			"\0"
-#endif
-#endif
-#ifdef	CONFIG_ENV_ACL_DEFAULT
-	"acl="		CONFIG_ENV_ACL_DEFAULT		"\0"
-#endif
-#ifdef	CONFIG_EXTRA_ENV_SETTINGS
-	CONFIG_EXTRA_ENV_SETTINGS
-#endif
-	"\0"
-};
+#include <env_default.h>
 
 struct hsearch_data env_htab;
 
diff --git a/common/env_embedded.c b/common/env_embedded.c
index 949fb95..f8d633a 100644
--- a/common/env_embedded.c
+++ b/common/env_embedded.c
@@ -81,13 +81,6 @@
 	GEN_SET_VALUE(name, value)
 
 /*
- * Macros to transform values
- * into environment strings.
- */
-#define XMK_STR(x)	#x
-#define MK_STR(x)	XMK_STR(x)
-
-/*
  * Check to see if we are building with a
  * computed CRC.  Otherwise define it as ~0.
  */
@@ -95,110 +88,9 @@
 #  define ENV_CRC	(~0)
 #endif
 
-env_t environment __PPCENV__ = {
-	ENV_CRC,	/* CRC Sum */
-#ifdef CONFIG_SYS_REDUNDAND_ENVIRONMENT
-	1,		/* Flags: valid */
-#endif
-	{
-#if defined(CONFIG_BOOTARGS)
-	"bootargs="	CONFIG_BOOTARGS			"\0"
-#endif
-#if defined(CONFIG_BOOTCOMMAND)
-	"bootcmd="	CONFIG_BOOTCOMMAND		"\0"
-#endif
-#if defined(CONFIG_RAMBOOTCOMMAND)
-	"ramboot="	CONFIG_RAMBOOTCOMMAND		"\0"
-#endif
-#if defined(CONFIG_NFSBOOTCOMMAND)
-	"nfsboot="	CONFIG_NFSBOOTCOMMAND		"\0"
-#endif
-#if defined(CONFIG_BOOTDELAY) && (CONFIG_BOOTDELAY >= 0)
-	"bootdelay="	MK_STR(CONFIG_BOOTDELAY)	"\0"
-#endif
-#if defined(CONFIG_BAUDRATE) && (CONFIG_BAUDRATE >= 0)
-	"baudrate="	MK_STR(CONFIG_BAUDRATE)		"\0"
-#endif
-#ifdef	CONFIG_LOADS_ECHO
-	"loads_echo="	MK_STR(CONFIG_LOADS_ECHO)	"\0"
-#endif
-#ifdef	CONFIG_ETHADDR
-	"ethaddr="	MK_STR(CONFIG_ETHADDR)		"\0"
-#endif
-#ifdef	CONFIG_ETH1ADDR
-	"eth1addr="	MK_STR(CONFIG_ETH1ADDR)		"\0"
-#endif
-#ifdef	CONFIG_ETH2ADDR
-	"eth2addr="	MK_STR(CONFIG_ETH2ADDR)		"\0"
-#endif
-#ifdef	CONFIG_ETH3ADDR
-	"eth3addr="	MK_STR(CONFIG_ETH3ADDR)		"\0"
-#endif
-#ifdef	CONFIG_ETH4ADDR
-	"eth4addr="	MK_STR(CONFIG_ETH4ADDR)		"\0"
-#endif
-#ifdef	CONFIG_ETH5ADDR
-	"eth5addr="	MK_STR(CONFIG_ETH5ADDR)		"\0"
-#endif
-#ifdef	CONFIG_ETHPRIME
-	"ethprime="	CONFIG_ETHPRIME			"\0"
-#endif
-#ifdef	CONFIG_IPADDR
-	"ipaddr="	MK_STR(CONFIG_IPADDR)		"\0"
-#endif
-#ifdef	CONFIG_SERVERIP
-	"serverip="	MK_STR(CONFIG_SERVERIP)		"\0"
-#endif
-#ifdef	CONFIG_SYS_AUTOLOAD
-	"autoload="	CONFIG_SYS_AUTOLOAD		"\0"
-#endif
-#ifdef	CONFIG_ROOTPATH
-	"rootpath="	CONFIG_ROOTPATH			"\0"
-#endif
-#ifdef	CONFIG_GATEWAYIP
-	"gatewayip="	MK_STR(CONFIG_GATEWAYIP)	"\0"
-#endif
-#ifdef	CONFIG_NETMASK
-	"netmask="	MK_STR(CONFIG_NETMASK)		"\0"
-#endif
-#ifdef	CONFIG_HOSTNAME
-	"hostname="	MK_STR(CONFIG_HOSTNAME)		"\0"
-#endif
-#ifdef	CONFIG_BOOTFILE
-	"bootfile="	CONFIG_BOOTFILE			"\0"
-#endif
-#ifdef	CONFIG_LOADADDR
-	"loadaddr="	MK_STR(CONFIG_LOADADDR)		"\0"
-#endif
-#ifdef	CONFIG_PREBOOT
-	"preboot="	CONFIG_PREBOOT			"\0"
-#endif
-#ifdef	CONFIG_CLOCKS_IN_MHZ
-	"clocks_in_mhz=" "1"				"\0"
-#endif
-#if defined(CONFIG_PCI_BOOTDELAY) && (CONFIG_PCI_BOOTDELAY > 0)
-	"pcidelay="	MK_STR(CONFIG_PCI_BOOTDELAY)	"\0"
-#endif
-#ifdef	CONFIG_ENV_VARS_UBOOT_CONFIG
-	"arch="		CONFIG_SYS_ARCH			"\0"
-	"cpu="		CONFIG_SYS_CPU			"\0"
-	"board="	CONFIG_SYS_BOARD		"\0"
-#ifdef CONFIG_SYS_VENDOR
-	"vendor="	CONFIG_SYS_VENDOR		"\0"
-#endif
-#ifdef CONFIG_SYS_SOC
-	"soc="		CONFIG_SYS_SOC			"\0"
-#endif
-#endif
-#ifdef	CONFIG_ENV_ACL_DEFAULT
-	"acl="		CONFIG_ENV_ACL_DEFAULT		"\0"
-#endif
-#ifdef	CONFIG_EXTRA_ENV_SETTINGS
-	CONFIG_EXTRA_ENV_SETTINGS
-#endif
-	"\0"		/* Term. env_t.data with 2 NULs */
-	}
-};
+#define DEFAULT_ENV_INSTANCE_EMBEDDED
+#include <env_default.h>
+
 #ifdef CONFIG_ENV_ADDR_REDUND
 env_t redundand_environment __PPCENV__ = {
 	0,		/* CRC Sum: invalid */
diff --git a/include/env_default.h b/include/env_default.h
new file mode 100644
index 0000000..98dc031
--- /dev/null
+++ b/include/env_default.h
@@ -0,0 +1,142 @@
+/*
+ * (C) Copyright 2000-2010
+ * Wolfgang Denk, DENX Software Engineering, wd at denx.de.
+ *
+ * (C) Copyright 2001 Sysgo Real-Time Solutions, GmbH <www.elinos.com>
+ * Andreas Heppel <aheppel@sysgo.de>
+ *
+ * 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
+ */
+
+/*
+ * Macros to transform values
+ * into environment strings.
+ */
+#define XMK_STR(x)	#x
+#define MK_STR(x)	XMK_STR(x)
+
+#ifdef DEFAULT_ENV_INSTANCE_EMBEDDED
+env_t environment __PPCENV__ = {
+	ENV_CRC,	/* CRC Sum */
+#ifdef CONFIG_SYS_REDUNDAND_ENVIRONMENT
+	1,		/* Flags: valid */
+#endif
+	{
+#elif defined(DEFAULT_ENV_INSTANCE_STATIC)
+static char default_environment[] = {
+#else
+const uchar default_environment[] = {
+#endif
+#ifdef	CONFIG_BOOTARGS
+	"bootargs="	CONFIG_BOOTARGS			"\0"
+#endif
+#ifdef	CONFIG_BOOTCOMMAND
+	"bootcmd="	CONFIG_BOOTCOMMAND		"\0"
+#endif
+#ifdef	CONFIG_RAMBOOTCOMMAND
+	"ramboot="	CONFIG_RAMBOOTCOMMAND		"\0"
+#endif
+#ifdef	CONFIG_NFSBOOTCOMMAND
+	"nfsboot="	CONFIG_NFSBOOTCOMMAND		"\0"
+#endif
+#if defined(CONFIG_BOOTDELAY) && (CONFIG_BOOTDELAY >= 0)
+	"bootdelay="	MK_STR(CONFIG_BOOTDELAY)	"\0"
+#endif
+#if defined(CONFIG_BAUDRATE) && (CONFIG_BAUDRATE >= 0)
+	"baudrate="	MK_STR(CONFIG_BAUDRATE)		"\0"
+#endif
+#ifdef	CONFIG_LOADS_ECHO
+	"loads_echo="	MK_STR(CONFIG_LOADS_ECHO)	"\0"
+#endif
+#ifdef	CONFIG_ETHADDR
+	"ethaddr="	MK_STR(CONFIG_ETHADDR)		"\0"
+#endif
+#ifdef	CONFIG_ETH1ADDR
+	"eth1addr="	MK_STR(CONFIG_ETH1ADDR)		"\0"
+#endif
+#ifdef	CONFIG_ETH2ADDR
+	"eth2addr="	MK_STR(CONFIG_ETH2ADDR)		"\0"
+#endif
+#ifdef	CONFIG_ETH3ADDR
+	"eth3addr="	MK_STR(CONFIG_ETH3ADDR)		"\0"
+#endif
+#ifdef	CONFIG_ETH4ADDR
+	"eth4addr="	MK_STR(CONFIG_ETH4ADDR)		"\0"
+#endif
+#ifdef	CONFIG_ETH5ADDR
+	"eth5addr="	MK_STR(CONFIG_ETH5ADDR)		"\0"
+#endif
+#ifdef	CONFIG_IPADDR
+	"ipaddr="	MK_STR(CONFIG_IPADDR)		"\0"
+#endif
+#ifdef	CONFIG_SERVERIP
+	"serverip="	MK_STR(CONFIG_SERVERIP)		"\0"
+#endif
+#ifdef	CONFIG_SYS_AUTOLOAD
+	"autoload="	CONFIG_SYS_AUTOLOAD		"\0"
+#endif
+#ifdef	CONFIG_PREBOOT
+	"preboot="	CONFIG_PREBOOT			"\0"
+#endif
+#ifdef	CONFIG_ROOTPATH
+	"rootpath="	CONFIG_ROOTPATH			"\0"
+#endif
+#ifdef	CONFIG_GATEWAYIP
+	"gatewayip="	MK_STR(CONFIG_GATEWAYIP)	"\0"
+#endif
+#ifdef	CONFIG_NETMASK
+	"netmask="	MK_STR(CONFIG_NETMASK)		"\0"
+#endif
+#ifdef	CONFIG_HOSTNAME
+	"hostname="	MK_STR(CONFIG_HOSTNAME)		"\0"
+#endif
+#ifdef	CONFIG_BOOTFILE
+	"bootfile="	CONFIG_BOOTFILE			"\0"
+#endif
+#ifdef	CONFIG_LOADADDR
+	"loadaddr="	MK_STR(CONFIG_LOADADDR)		"\0"
+#endif
+#ifdef	CONFIG_CLOCKS_IN_MHZ
+	"clocks_in_mhz=1\0"
+#endif
+#if defined(CONFIG_PCI_BOOTDELAY) && (CONFIG_PCI_BOOTDELAY > 0)
+	"pcidelay="	MK_STR(CONFIG_PCI_BOOTDELAY)	"\0"
+#endif
+#ifdef	CONFIG_ENV_VARS_UBOOT_CONFIG
+	"arch="		CONFIG_SYS_ARCH			"\0"
+	"cpu="		CONFIG_SYS_CPU			"\0"
+	"board="	CONFIG_SYS_BOARD		"\0"
+#ifdef CONFIG_SYS_VENDOR
+	"vendor="	CONFIG_SYS_VENDOR		"\0"
+#endif
+#ifdef CONFIG_SYS_SOC
+	"soc="		CONFIG_SYS_SOC			"\0"
+#endif
+#endif
+#ifdef	CONFIG_ENV_ACL_DEFAULT
+	"acl="		CONFIG_ENV_ACL_DEFAULT		"\0"
+#endif
+#ifdef	CONFIG_EXTRA_ENV_SETTINGS
+	CONFIG_EXTRA_ENV_SETTINGS
+#endif
+	"\0"
+#ifdef DEFAULT_ENV_INSTANCE_EMBEDDED
+	}
+#endif
+};
diff --git a/tools/env/fw_env.c b/tools/env/fw_env.c
index 60ff06c..e5e5023 100644
--- a/tools/env/fw_env.c
+++ b/tools/env/fw_env.c
@@ -118,97 +118,8 @@ static unsigned char active_flag = 1;
 /* obsolete_flag must be 0 to efficiently set it on NOR flash without erasing */
 static unsigned char obsolete_flag = 0;
 
-
-#define XMK_STR(x)	#x
-#define MK_STR(x)	XMK_STR(x)
-
-static char default_environment[] = {
-#if defined(CONFIG_BOOTARGS)
-	"bootargs=" CONFIG_BOOTARGS "\0"
-#endif
-#if defined(CONFIG_BOOTCOMMAND)
-	"bootcmd=" CONFIG_BOOTCOMMAND "\0"
-#endif
-#if defined(CONFIG_RAMBOOTCOMMAND)
-	"ramboot=" CONFIG_RAMBOOTCOMMAND "\0"
-#endif
-#if defined(CONFIG_NFSBOOTCOMMAND)
-	"nfsboot=" CONFIG_NFSBOOTCOMMAND "\0"
-#endif
-#if defined(CONFIG_BOOTDELAY) && (CONFIG_BOOTDELAY >= 0)
-	"bootdelay=" MK_STR (CONFIG_BOOTDELAY) "\0"
-#endif
-#if defined(CONFIG_BAUDRATE) && (CONFIG_BAUDRATE >= 0)
-	"baudrate=" MK_STR (CONFIG_BAUDRATE) "\0"
-#endif
-#ifdef	CONFIG_LOADS_ECHO
-	"loads_echo=" MK_STR (CONFIG_LOADS_ECHO) "\0"
-#endif
-#ifdef	CONFIG_ETHADDR
-	"ethaddr=" MK_STR (CONFIG_ETHADDR) "\0"
-#endif
-#ifdef	CONFIG_ETH1ADDR
-	"eth1addr=" MK_STR (CONFIG_ETH1ADDR) "\0"
-#endif
-#ifdef	CONFIG_ETH2ADDR
-	"eth2addr=" MK_STR (CONFIG_ETH2ADDR) "\0"
-#endif
-#ifdef	CONFIG_ETH3ADDR
-	"eth3addr=" MK_STR (CONFIG_ETH3ADDR) "\0"
-#endif
-#ifdef	CONFIG_ETH4ADDR
-	"eth4addr=" MK_STR (CONFIG_ETH4ADDR) "\0"
-#endif
-#ifdef	CONFIG_ETH5ADDR
-	"eth5addr=" MK_STR (CONFIG_ETH5ADDR) "\0"
-#endif
-#ifdef	CONFIG_ETHPRIME
-	"ethprime=" CONFIG_ETHPRIME "\0"
-#endif
-#ifdef	CONFIG_IPADDR
-	"ipaddr=" MK_STR (CONFIG_IPADDR) "\0"
-#endif
-#ifdef	CONFIG_SERVERIP
-	"serverip=" MK_STR (CONFIG_SERVERIP) "\0"
-#endif
-#ifdef	CONFIG_SYS_AUTOLOAD
-	"autoload=" CONFIG_SYS_AUTOLOAD "\0"
-#endif
-#ifdef	CONFIG_ROOTPATH
-	"rootpath=" CONFIG_ROOTPATH "\0"
-#endif
-#ifdef	CONFIG_GATEWAYIP
-	"gatewayip=" MK_STR (CONFIG_GATEWAYIP) "\0"
-#endif
-#ifdef	CONFIG_NETMASK
-	"netmask=" MK_STR (CONFIG_NETMASK) "\0"
-#endif
-#ifdef	CONFIG_HOSTNAME
-	"hostname=" MK_STR (CONFIG_HOSTNAME) "\0"
-#endif
-#ifdef	CONFIG_BOOTFILE
-	"bootfile=" CONFIG_BOOTFILE "\0"
-#endif
-#ifdef	CONFIG_LOADADDR
-	"loadaddr=" MK_STR (CONFIG_LOADADDR) "\0"
-#endif
-#ifdef	CONFIG_PREBOOT
-	"preboot=" CONFIG_PREBOOT "\0"
-#endif
-#ifdef	CONFIG_CLOCKS_IN_MHZ
-	"clocks_in_mhz=" "1" "\0"
-#endif
-#if defined(CONFIG_PCI_BOOTDELAY) && (CONFIG_PCI_BOOTDELAY > 0)
-	"pcidelay=" MK_STR (CONFIG_PCI_BOOTDELAY) "\0"
-#endif
-#ifdef	CONFIG_ENV_ACL_DEFAULT
-	"acl=" CONFIG_ENV_ACL_DEFAULT "\0"
-#endif
-#ifdef  CONFIG_EXTRA_ENV_SETTINGS
-	CONFIG_EXTRA_ENV_SETTINGS
-#endif
-	"\0"		/* Termimate struct environment data with 2 NULs */
-};
+#define DEFAULT_ENV_INSTANCE_STATIC
+#include <env_default.h>
 
 static int flash_io (int mode);
 static char *envmatch (char * s1, char * s2);
-- 
1.7.11.5

^ permalink raw reply related	[flat|nested] 124+ messages in thread

* [U-Boot] [PATCH 08/12] env: Check for NULL pointer in envmatch()
  2012-08-17 20:49                               ` [U-Boot] [PATCH 08/12] env: Check for NULL pointer in envmatch() Joe Hershberger
@ 2012-08-17 23:51                                 ` Mike Frysinger
  0 siblings, 0 replies; 124+ messages in thread
From: Mike Frysinger @ 2012-08-17 23:51 UTC (permalink / raw)
  To: u-boot

On Friday 17 August 2012 16:49:42 Joe Hershberger wrote:
> If the pointer passed into envmatch() is NULL, return -1 instead of
> crashing.

so don't pass in NULL ?
-mike
-------------- next part --------------
A non-text attachment was scrubbed...
Name: not available
Type: application/pgp-signature
Size: 836 bytes
Desc: This is a digitally signed message part.
URL: <http://lists.denx.de/pipermail/u-boot/attachments/20120817/96547e5e/attachment.pgp>

^ permalink raw reply	[flat|nested] 124+ messages in thread

* [U-Boot] [PATCH 01/12] tools/env: Use a board-specific default env
  2012-08-17 20:49                               ` [U-Boot] [PATCH 01/12] tools/env: Use a board-specific default env Joe Hershberger
@ 2012-08-23  3:17                                 ` Mike Frysinger
  2012-08-23 15:45                                   ` Joe Hershberger
  0 siblings, 1 reply; 124+ messages in thread
From: Mike Frysinger @ 2012-08-23  3:17 UTC (permalink / raw)
  To: u-boot

On Friday 17 August 2012 16:49:35 Joe Hershberger wrote:
>   */
>  #define CONFIG_FILE     "/etc/fw_env.config"
> 
> +#ifndef CONFIG_FILE

this doesn't make any sense.  CONFIG_FILE is defined literally right above this 
check.
-mike
-------------- next part --------------
A non-text attachment was scrubbed...
Name: not available
Type: application/pgp-signature
Size: 836 bytes
Desc: This is a digitally signed message part.
URL: <http://lists.denx.de/pipermail/u-boot/attachments/20120822/993f3b22/attachment.pgp>

^ permalink raw reply	[flat|nested] 124+ messages in thread

* [U-Boot] [PATCH 02/12] tools/env: Remove unneeded complexity
  2012-08-17 20:49                               ` [U-Boot] [PATCH 02/12] tools/env: Remove unneeded complexity Joe Hershberger
@ 2012-08-23  3:30                                 ` Mike Frysinger
  0 siblings, 0 replies; 124+ messages in thread
From: Mike Frysinger @ 2012-08-23  3:30 UTC (permalink / raw)
  To: u-boot

On Friday 17 August 2012 16:49:36 Joe Hershberger wrote:
> --- a/tools/env/fw_env.c
> +++ b/tools/env/fw_env.c
> 
> -			memset(value, 0, len - strlen(name));
> +			memset(value, 0, len);

side note: this memset is mostly useles as the value buffer largely gets 
written.  all it should be is:
	value[len - 1] = '\0';

similarly, this logic at the end:
	if (value)
		free(value);
that "if" check is pointless as free(NULL) works fine

if you really wanted, the whole loop could be rewritten to use realloc

	for (i = 2; i < argc; ++i) {
		const char *val = argv[i];
		size_t val_len = strlen(val);

		value = realloc(value, len + val_len + 1);
		if (!value) {
			fprintf(...);
			return -1;
		}

		memcpy(value + len, val, val_len);
		len += val_len;
		value[len++] = ' ';
	}
	value[len - 1] = '\0';
-mike
-------------- next part --------------
A non-text attachment was scrubbed...
Name: not available
Type: application/pgp-signature
Size: 836 bytes
Desc: This is a digitally signed message part.
URL: <http://lists.denx.de/pipermail/u-boot/attachments/20120822/149260b8/attachment.pgp>

^ permalink raw reply	[flat|nested] 124+ messages in thread

* [U-Boot] [PATCH 04/12] tools/env: Reduce the impact on real-time processes
  2012-08-17 20:49                               ` [U-Boot] [PATCH 04/12] tools/env: Reduce the impact on real-time processes Joe Hershberger
@ 2012-08-23  3:30                                 ` Mike Frysinger
  2012-08-23 16:26                                   ` Joe Hershberger
  0 siblings, 1 reply; 124+ messages in thread
From: Mike Frysinger @ 2012-08-23  3:30 UTC (permalink / raw)
  To: u-boot

On Friday 17 August 2012 16:49:38 Joe Hershberger wrote:
> +		* Break reads up into very small chunks so fw_printenv doesn't
> +		* block the kernel long enough to starve other kernel tasks.

err, this sounds like a bug in your kernel driver.  why should userspace be 
working around buggy drivers ?
-mike
-------------- next part --------------
A non-text attachment was scrubbed...
Name: not available
Type: application/pgp-signature
Size: 836 bytes
Desc: This is a digitally signed message part.
URL: <http://lists.denx.de/pipermail/u-boot/attachments/20120822/c7284da5/attachment.pgp>

^ permalink raw reply	[flat|nested] 124+ messages in thread

* [U-Boot] [PATCH 05/12] tools/env: Serialize calls to fw_*env
  2012-08-17 20:49                               ` [U-Boot] [PATCH 05/12] tools/env: Serialize calls to fw_*env Joe Hershberger
@ 2012-08-23  3:33                                 ` Mike Frysinger
  2012-10-03  1:12                                   ` Joe Hershberger
  0 siblings, 1 reply; 124+ messages in thread
From: Mike Frysinger @ 2012-08-23  3:33 UTC (permalink / raw)
  To: u-boot

On Friday 17 August 2012 16:49:39 Joe Hershberger wrote:
> Use a lock file at /var/lock/fw_printenv.lock.

the lock should be per-MTD, not per-system.

> +	if (-1 == flock(lockfd, LOCK_EX)) {

i guess flock() on the fd returned from the mtd device itself doesn't work ?
-mike
-------------- next part --------------
A non-text attachment was scrubbed...
Name: not available
Type: application/pgp-signature
Size: 836 bytes
Desc: This is a digitally signed message part.
URL: <http://lists.denx.de/pipermail/u-boot/attachments/20120822/6ecf0b7f/attachment.pgp>

^ permalink raw reply	[flat|nested] 124+ messages in thread

* [U-Boot] [PATCH 06/12] env: Make the "silent" env var take effect immediately
  2012-08-17 20:49                               ` [U-Boot] [PATCH 06/12] env: Make the "silent" env var take effect immediately Joe Hershberger
@ 2012-08-23  3:35                                 ` Mike Frysinger
  0 siblings, 0 replies; 124+ messages in thread
From: Mike Frysinger @ 2012-08-23  3:35 UTC (permalink / raw)
  To: u-boot

On Friday 17 August 2012 16:49:40 Joe Hershberger wrote:
> --- a/common/cmd_nvedit.c
> +++ b/common/cmd_nvedit.c
>
> +#if defined(CONFIG_SILENT_CONSOLE) && \
> +	defined(CONFIG_SILENT_CONSOLE_UPDATE_ON_SET)

i wonder if the CONFIG_SILENT_CONSOLE check is needed.  setting the latter 
without the former doesn't make sense.

> +- CONFIG_SILENT_CONSOLE_UPDATE_ON_SET
> +	When the "silent" variable is changed with env set, the change
> +	will take effect immediately

should end in a "."
-mike
-------------- next part --------------
A non-text attachment was scrubbed...
Name: not available
Type: application/pgp-signature
Size: 836 bytes
Desc: This is a digitally signed message part.
URL: <http://lists.denx.de/pipermail/u-boot/attachments/20120822/ec2d8f06/attachment.pgp>

^ permalink raw reply	[flat|nested] 124+ messages in thread

* [U-Boot] [PATCH 10/12] env: acl: Add environment variable access control list
  2012-08-17 20:49                               ` [U-Boot] [PATCH 10/12] env: acl: Add environment variable access control list Joe Hershberger
@ 2012-08-23  3:43                                 ` Mike Frysinger
  2012-09-13 20:13                                 ` Wolfgang Denk
  1 sibling, 0 replies; 124+ messages in thread
From: Mike Frysinger @ 2012-08-23  3:43 UTC (permalink / raw)
  To: u-boot

On Friday 17 August 2012 16:49:44 Joe Hershberger wrote:
> --- a/common/cmd_nvedit.c
> +++ b/common/cmd_nvedit.c
>
> +#if defined(CONFIG_ENV_ACL)
> +#include <env_acl.h>
> +#endif

the header should not need protection just to be included

> +#ifdef CONFIG_ENV_ACL
> +	if (env_acl_validate_env_set_params(argc, argv) < 0)
> +		return 1;
> +#endif

have the header define env_acl_validate_env_set_params() as a return 0 static 
inline func when CONFIG_ENV_ACL isn't defined and then you can drop the ifdef 
here

> --- /dev/null
> +++ b/common/env_acl.c
>
> + * (C) Copyright 2010

fwiw, it's 2012 now

> +static int _env_acl_lookup_r(const char *name, char *attributes, int
> static_acl)
> ...
> +	entry = strstr(acl, name);
> +	while (entry != NULL) {
> +		if ((entry == acl || *(entry - 1) == ENV_ACL_LIST_DELIM ||
> +		    *(entry - 1) == ' ') &&
> +		    (*(entry + strlen(name)) == ENV_ACL_ATTR_SEP ||
> +		     *(entry + strlen(name)) == ENV_ACL_LIST_DELIM ||
> +		     *(entry + strlen(name)) == '\0' ||
> +		     *(entry + strlen(name)) == ' '))
> +			break;

is that strlen optimized away ?  i suspect not.  and even if it is, the 
duplication here is kind of ugly, so it'd be better to use a local var 
anyways.
	const char *acl_val = entry + strlen(name);

> +static int env_acl_lookup_r(const char *name, char *attributes)
> +{
> +	int ret_val;
> +	/* try the env first */
> +	ret_val = _env_acl_lookup_r(name, attributes, 0);
> +	if (ret_val != 0) {
> +		/* if not found in the env, look in the static list */
> +		ret_val = _env_acl_lookup_r(name, attributes, 1);
> +	}
> +	return ret_val;
> +}
> +
> +enum env_acl_var_type env_acl_get_type(const char *name)
> +{
> +	char *type;

const

> +static void skip_num(int hex, const char *value, const char **end,
> +	int max_digits)
> +{
> +	int i;
> +
> +	if (hex && is_hex_prefix(value))
> +		value += 2;
> +
> +	for (i = max_digits; i != 0; i--) {
> +		if (hex && !isxdigit(*value))
> +			break;
> +		if (!hex && !isdigit(*value))
> +			break;
> +		value++;
> +	}
> +	if (end != NULL)
> +		*end = value;
> +}

couldn't you use strtol and abuse the endptr field ?

> --- a/tools/env/fw_env.h
> +++ b/tools/env/fw_env.h
> 
> +#define min(x, y) ({				\
> +	typeof(x) _min1 = (x);			\
> +	typeof(y) _min2 = (y);			\
> +	(void) (&_min1 == &_min2);		\
> +	_min1 < _min2 ? _min1 : _min2; })

ugh, no.  use include/compiler.h.  you might want to look@the min/max 
already defined in include/common.h rather than duplicating another one 
locally.
-mike
-------------- next part --------------
A non-text attachment was scrubbed...
Name: not available
Type: application/pgp-signature
Size: 836 bytes
Desc: This is a digitally signed message part.
URL: <http://lists.denx.de/pipermail/u-boot/attachments/20120822/4371457d/attachment.pgp>

^ permalink raw reply	[flat|nested] 124+ messages in thread

* [U-Boot] [PATCH 12/12] env: cosmetic: Consilidate the default env definition
  2012-08-17 20:49                               ` [U-Boot] [PATCH 12/12] env: cosmetic: Consilidate the default env definition Joe Hershberger
@ 2012-08-23  3:44                                 ` Mike Frysinger
  0 siblings, 0 replies; 124+ messages in thread
From: Mike Frysinger @ 2012-08-23  3:44 UTC (permalink / raw)
  To: u-boot

On Friday 17 August 2012 16:49:46 Joe Hershberger wrote:
> There used to be a huge structure duplicated 3 times in the source.

if this actually works:
Acked-by: Mike Frysinger <vapier@gentoo.org>
-mike
-------------- next part --------------
A non-text attachment was scrubbed...
Name: not available
Type: application/pgp-signature
Size: 836 bytes
Desc: This is a digitally signed message part.
URL: <http://lists.denx.de/pipermail/u-boot/attachments/20120822/a1677d38/attachment.pgp>

^ permalink raw reply	[flat|nested] 124+ messages in thread

* [U-Boot] [PATCH 01/12] tools/env: Use a board-specific default env
  2012-08-23  3:17                                 ` Mike Frysinger
@ 2012-08-23 15:45                                   ` Joe Hershberger
  0 siblings, 0 replies; 124+ messages in thread
From: Joe Hershberger @ 2012-08-23 15:45 UTC (permalink / raw)
  To: u-boot

Hi Mike,

On Wed, Aug 22, 2012 at 10:17 PM, Mike Frysinger <vapier@gentoo.org> wrote:
> On Friday 17 August 2012 16:49:35 Joe Hershberger wrote:
>>   */
>>  #define CONFIG_FILE     "/etc/fw_env.config"
>>
>> +#ifndef CONFIG_FILE
>
> this doesn't make any sense.  CONFIG_FILE is defined literally right above this
> check.

The comment right above that says:

/*
 * To build the utility with the static configuration
 * comment out the next line.
 * See included "fw_env.config" sample file
 * for notes on configuration.
 */

...so the reason for the #ifndef is for the case where you comment out
that line.  The other option is to just delete all of that stuff and
the user can add it all back if they want to operate with no config
file.

-Joe

^ permalink raw reply	[flat|nested] 124+ messages in thread

* [U-Boot] [PATCH 04/12] tools/env: Reduce the impact on real-time processes
  2012-08-23  3:30                                 ` Mike Frysinger
@ 2012-08-23 16:26                                   ` Joe Hershberger
  2012-08-23 20:31                                     ` Mike Frysinger
  0 siblings, 1 reply; 124+ messages in thread
From: Joe Hershberger @ 2012-08-23 16:26 UTC (permalink / raw)
  To: u-boot

Hi Mike,

On Wed, Aug 22, 2012 at 10:30 PM, Mike Frysinger <vapier@gentoo.org> wrote:
> On Friday 17 August 2012 16:49:38 Joe Hershberger wrote:
>> +             * Break reads up into very small chunks so fw_printenv doesn't
>> +             * block the kernel long enough to starve other kernel tasks.
>
> err, this sounds like a bug in your kernel driver.  why should userspace be
> working around buggy drivers ?

The problem is something to do with the mtd driver blocking some
resource on large reads that starves USB transfers.  We never fully
investigated it.  It's true that this is a work-around.  Is that so
bad?  Maybe so.

-Joe

^ permalink raw reply	[flat|nested] 124+ messages in thread

* [U-Boot] [PATCH 04/12] tools/env: Reduce the impact on real-time processes
  2012-08-23 16:26                                   ` Joe Hershberger
@ 2012-08-23 20:31                                     ` Mike Frysinger
  0 siblings, 0 replies; 124+ messages in thread
From: Mike Frysinger @ 2012-08-23 20:31 UTC (permalink / raw)
  To: u-boot

On Thursday 23 August 2012 12:26:08 Joe Hershberger wrote:
> On Wed, Aug 22, 2012 at 10:30 PM, Mike Frysinger wrote:
> > On Friday 17 August 2012 16:49:38 Joe Hershberger wrote:
> >> +	* Break reads up into very small chunks so fw_printenv doesn't
> >> +	* block the kernel long enough to starve other kernel tasks.
> > 
> > err, this sounds like a bug in your kernel driver.  why should userspace
> > be working around buggy drivers ?
> 
> The problem is something to do with the mtd driver blocking some
> resource on large reads that starves USB transfers.  We never fully
> investigated it.  It's true that this is a work-around.  Is that so
> bad?  Maybe so.

i think it's a bad precedent that we shouldn't encourage.  you add your wonky 
hardware workaround, and then the next guy will want to add his hack for their 
broken driver, and we're left with an ugly unmaintainable pile.
-mike
-------------- next part --------------
A non-text attachment was scrubbed...
Name: not available
Type: application/pgp-signature
Size: 836 bytes
Desc: This is a digitally signed message part.
URL: <http://lists.denx.de/pipermail/u-boot/attachments/20120823/9de1e230/attachment.pgp>

^ permalink raw reply	[flat|nested] 124+ messages in thread

* [U-Boot] [PATCH 10/12] env: acl: Add environment variable access control list
  2012-08-17 20:49                               ` [U-Boot] [PATCH 10/12] env: acl: Add environment variable access control list Joe Hershberger
  2012-08-23  3:43                                 ` Mike Frysinger
@ 2012-09-13 20:13                                 ` Wolfgang Denk
  2012-09-14  2:24                                   ` Joe Hershberger
  1 sibling, 1 reply; 124+ messages in thread
From: Wolfgang Denk @ 2012-09-13 20:13 UTC (permalink / raw)
  To: u-boot

Dear Joe Hershberger,

In message <1345236586-19076-11-git-send-email-joe.hershberger@ni.com> you wrote:
> Currently just validates variable types as decimal, hexidecimal,
> boolean, ip address, and mac address.  Call
> env_acl_validate_setenv_params() from setenv() in both cmd_nvedit.c
> and fw_env.c.
> 
> If the entry is not found in the env ACL, then look in the static one.
> This allows the env to override the static definitions, but prevents
> the need to have every definition in the environment distracting you.

I have to admid that I haven't tested your code at all, but here are
a few comments anyway:

- It appears you will store all access related information in the ACL
  variable (or a copy of it), i. e. in linearized form.  Are you not
  concerned that this will make variable access slow?

- Encoding type information in a variable named "acl" doesn;t look
  really elegant to me.  Of course, chosing another name is a trivial
  thing to do.

- There have been discussions that it would be nice to have a
  "volatile" variable type, for example for variables like "filesize"
  or "loadaddr" - such variables would not be stored to the persistent
  storage by the "saveenv" command.  Thi sis something that should be
  fairly wasy to add to your code.

- It would be nice if we could group variables; for example, assume we
  could define a group "network" which includes things like ethaddr,
  ipaddr, netmask, hostname etc. - and we could then do something like
  "env print -g network" to print all variables of such a group.

- We have the situation that certain variables need specific handling
  when they get assigned to - baudrate, ethaddr etc. come to mind.
  But the code to implement this is scattered all over the place, nd
  doesn't really scale.

I've been thinking about similar features for some time, but the
implementation I had in mind was way different.  This is what I had in
mind:

- Like you, I wanted to use plain environment variables for
  persistent storage of all such information. The format you chose
  looks fine for me, too.

- I would like to flag these variables as special by using special
  names for them. All such special vailables would start with a dot,
  i. e. instead of "acl" I had planned to call this ".flags".

  Normally "env print" etc. would not show such specal variables, but
  "env print -a" would.

  Similarly, grous of variables could be defined in a ".groups"
  variable, etc.

- Instead of parsing the ".flags" variable again and again when
  accessing variables, my idea was to extend the hash table: so far,
  the struct entry (see "include/search.h") holds only pointers to the
  key (variable name) and data (variable value).  I suggest to
  extend this struct:

  * By adding a field "flags" (u32) we could easily encode access
    permission type information (like read-only, write-once,
    volatile, ...), and of course also type information (hex, dec,
    string, IP addr, MAC addr, ...).

  * By adding a field "callbacks" (int foo(const char *)) we could
    register pointers to a function which gets called whenever the
    respective variable value gets changed.

    We would still need a compile time mapping from strings to
    pointers, but at least this would allow to generalize and unify
    the existing code. For example, setting up a mapping of string
    "ethaddr" to function env_set_ethaddr() would allow to create
    something like a special variable

    .callbacks=ethaddr:ethaddr,eth1addr,ath2addr;baudrate:baudrate;...

    This way we could even enale user specific callbacks without need
    to modify any common code.

    And any "env set" would just have to check if the callback
    function pointer is non-NULL ...
 

What do you think?

Best regards,

Wolfgang Denk

-- 
DENX Software Engineering GmbH,     MD: Wolfgang Denk & Detlev Zundel
HRB 165235 Munich, Office: Kirchenstr.5, D-82194 Groebenzell, Germany
Phone: (+49)-8142-66989-10 Fax: (+49)-8142-66989-80 Email: wd at denx.de
Too many people are ready to carry the stool when the piano needs  to
be moved.

^ permalink raw reply	[flat|nested] 124+ messages in thread

* [U-Boot] [PATCH 10/12] env: acl: Add environment variable access control list
  2012-09-13 20:13                                 ` Wolfgang Denk
@ 2012-09-14  2:24                                   ` Joe Hershberger
  2012-09-14 18:42                                     ` Wolfgang Denk
  0 siblings, 1 reply; 124+ messages in thread
From: Joe Hershberger @ 2012-09-14  2:24 UTC (permalink / raw)
  To: u-boot

Hi Wolfgang,

I guess you didn't see this the last time I sent it to you off list...

On Thu, Sep 13, 2012 at 3:13 PM, Wolfgang Denk <wd@denx.de> wrote:
> Dear Joe Hershberger,
>
> In message <1345236586-19076-11-git-send-email-joe.hershberger@ni.com> you wrote:
>> Currently just validates variable types as decimal, hexidecimal,
>> boolean, ip address, and mac address.  Call
>> env_acl_validate_setenv_params() from setenv() in both cmd_nvedit.c
>> and fw_env.c.
>>
>> If the entry is not found in the env ACL, then look in the static one.
>> This allows the env to override the static definitions, but prevents
>> the need to have every definition in the environment distracting you.
>
> I have to admid that I haven't tested your code at all, but here are
> a few comments anyway:
>
> - It appears you will store all access related information in the ACL
>   variable (or a copy of it), i. e. in linearized form.  Are you not
>   concerned that this will make variable access slow?

At least in my uses so far, there are not so many variables that it is
noticeably slower.

> - Encoding type information in a variable named "acl" doesn;t look
>   really elegant to me.  Of course, chosing another name is a trivial
>   thing to do.

For sure.  I accept that this is only one of the things it does and
it's not really access control in the typical sense (with users and
what not).

> - There have been discussions that it would be nice to have a
>   "volatile" variable type, for example for variables like "filesize"
>   or "loadaddr" - such variables would not be stored to the persistent
>   storage by the "saveenv" command.  Thi sis something that should be
>   fairly wasy to add to your code.

I was one of the proponents of this when we last discussed this some
years ago.  I left it out because you convinced me I should just use
other variables and overwrite the special ones in a script when I need
to.  I still think supporting a volatile variable would be cleaner
than that.  I'm glad you changed your mind.

> - It would be nice if we could group variables; for example, assume we
>   could define a group "network" which includes things like ethaddr,
>   ipaddr, netmask, hostname etc. - and we could then do something like
>   "env print -g network" to print all variables of such a group.

I agree that would be nice.

> - We have the situation that certain variables need specific handling
>   when they get assigned to - baudrate, ethaddr etc. come to mind.
>   But the code to implement this is scattered all over the place, nd
>   doesn't really scale.

I agree wholeheartedly.

> I've been thinking about similar features for some time, but the
> implementation I had in mind was way different.  This is what I had in
> mind:
>
> - Like you, I wanted to use plain environment variables for
>   persistent storage of all such information. The format you chose
>   looks fine for me, too.
>
> - I would like to flag these variables as special by using special
>   names for them. All such special vailables would start with a dot,
>   i. e. instead of "acl" I had planned to call this ".flags".

OK...  I like the prepended '.'.  I'm not sure that "flags" is a very
good name for something so specific from a user point of view, but I
see why you chose it based on how you plan to store it in the hash.

>   Normally "env print" etc. would not show such specal variables, but
>   "env print -a" would.

That makes sense.

>   Similarly, grous of variables could be defined in a ".groups"
>   variable, etc.

OK.

> - Instead of parsing the ".flags" variable again and again when
>   accessing variables, my idea was to extend the hash table: so far,
>   the struct entry (see "include/search.h") holds only pointers to the
>   key (variable name) and data (variable value).  I suggest to
>   extend this struct:

This seems like a good idea for the most part.  Are you concerned that
the hast table will take twice the space?  Should this be optional?

>   * By adding a field "flags" (u32) we could easily encode access
>     permission type information (like read-only, write-once,
>     volatile, ...), and of course also type information (hex, dec,
>     string, IP addr, MAC addr, ...).
>
>   * By adding a field "callbacks" (int foo(const char *)) we could
>     register pointers to a function which gets called whenever the
>     respective variable value gets changed.
>
>     We would still need a compile time mapping from strings to
>     pointers, but at least this would allow to generalize and unify
>     the existing code. For example, setting up a mapping of string
>     "ethaddr" to function env_set_ethaddr() would allow to create
>     something like a special variable
>
>     .callbacks=ethaddr:ethaddr,eth1addr,ath2addr;baudrate:baudrate;...

One of the things I've run into with baudrate and silent specifically
is wanting to control if the special callback is made on set and/or on
env relocation, and/or on initial load, and/or on import.  I think
there should be a field in the flags for when to check the callback.

>     This way we could even enale user specific callbacks without need
>     to modify any common code.

Would the user be able to define other callbacks somehow?

>     And any "env set" would just have to check if the callback
>     function pointer is non-NULL ...
>
>
> What do you think?

I think is sounds very nice.  And it's not too far from what I've
done.  I'll look into implementing some of it.

Cheers,
-Joe

^ permalink raw reply	[flat|nested] 124+ messages in thread

* [U-Boot] [PATCH 10/12] env: acl: Add environment variable access control list
  2012-09-14  2:24                                   ` Joe Hershberger
@ 2012-09-14 18:42                                     ` Wolfgang Denk
  2012-11-01 16:39                                       ` [U-Boot] [PATCH v3 0/18] Add environment call-back and flags capability Joe Hershberger
  0 siblings, 1 reply; 124+ messages in thread
From: Wolfgang Denk @ 2012-09-14 18:42 UTC (permalink / raw)
  To: u-boot

Dear Joe Hershberger,

In message <CANr=Z=b6wJCOxVc+zi6riiU4Smv5tv_5ifS1d9Ue8Ncv+xVLyg@mail.gmail.com> you wrote:
> 
> I guess you didn't see this the last time I sent it to you off list...

I didn't receive any such reply, sorry.  Do you have the message ID
and/or exact timestanmp of your message?


> > - It appears you will store all access related information in the ACL
> >   variable (or a copy of it), i. e. in linearized form.  Are you not
> >   concerned that this will make variable access slow?
> 
> At least in my uses so far, there are not so many variables that it is
> noticeably slower.

Did you run any benchmarks?

Note that in the linearized form not only the variable count, but also
to total size of their values plays a role.

> > - There have been discussions that it would be nice to have a
> >   "volatile" variable type, for example for variables like "filesize"
> >   or "loadaddr" - such variables would not be stored to the persistent
> >   storage by the "saveenv" command.  Thi sis something that should be
> >   fairly wasy to add to your code.
> 
> I was one of the proponents of this when we last discussed this some
> years ago.  I left it out because you convinced me I should just use
> other variables and overwrite the special ones in a script when I need
> to.  I still think supporting a volatile variable would be cleaner
> than that.  I'm glad you changed your mind.

I always try to listen to what people tell me :-)

> > - Instead of parsing the ".flags" variable again and again when
> >   accessing variables, my idea was to extend the hash table: so far,
> >   the struct entry (see "include/search.h") holds only pointers to the
> >   key (variable name) and data (variable value).  I suggest to
> >   extend this struct:
> 
> This seems like a good idea for the most part.  Are you concerned that
> the hast table will take twice the space?  Should this be optional?

The hash table lives in RAM only, which is usually an ample resource
these days.  I suggest to make the ".flags" support unconditional, but
".groups" support is probably not needed by many users, so this should
be optional.

So the default configuration whould have only a 50% increase of the
hash table size.

> >     .callbacks=ethaddr:ethaddr,eth1addr,ath2addr;baudrate:baudrate;...
> 
> One of the things I've run into with baudrate and silent specifically
> is wanting to control if the special callback is made on set and/or on
> env relocation, and/or on initial load, and/or on import.  I think
> there should be a field in the flags for when to check the callback.

I don't see the need for this distinction, yet.  My gut feeling is
that the callback should be run when the varibale value in the hash
table is being changed - relocation should play no role then, and
initial import, "env set", "env import" (including variable deletion)
should IMO all be handled the same.

I'd really like to make this code more simple.

> >     This way we could even enale user specific callbacks without need
> >     to modify any common code.
> 
> Would the user be able to define other callbacks somehow?

Yes.  Similar as he can add "private" U-Boot commands in his board
specific code, he should be able to add "private" callbacks.

> I think is sounds very nice.  And it's not too far from what I've
> done.  I'll look into implementing some of it.

I was hoping for such a reply :-)

Thanks a lot in advance.


Best regards,

Wolfgang Denk

-- 
DENX Software Engineering GmbH,     MD: Wolfgang Denk & Detlev Zundel
HRB 165235 Munich, Office: Kirchenstr.5, D-82194 Groebenzell, Germany
Phone: (+49)-8142-66989-10 Fax: (+49)-8142-66989-80 Email: wd at denx.de
PLEASE NOTE: Some Quantum Physics Theories Suggest That When the Con-
sumer Is Not Directly Observing This Product, It May Cease  to  Exist
or Will Exist Only in a Vague and Undetermined State.

^ permalink raw reply	[flat|nested] 124+ messages in thread

* [U-Boot] [PATCH 05/12] tools/env: Serialize calls to fw_*env
  2012-08-23  3:33                                 ` Mike Frysinger
@ 2012-10-03  1:12                                   ` Joe Hershberger
  0 siblings, 0 replies; 124+ messages in thread
From: Joe Hershberger @ 2012-10-03  1:12 UTC (permalink / raw)
  To: u-boot

Hi Mike,

Sorry for the delay... I've been distracted.

On Wed, Aug 22, 2012 at 10:33 PM, Mike Frysinger <vapier@gentoo.org> wrote:
> On Friday 17 August 2012 16:49:39 Joe Hershberger wrote:
>> Use a lock file at /var/lock/fw_printenv.lock.
>
> the lock should be per-MTD, not per-system.

I'm not sure that's the case.  The idea is to prevent the tool from
running more than once at a time.  I don't think it matters which mtd
is being accessed as we want all the mtd accesses across the whole
operation to be atomic.

If you are talking about having two independent sets of environments
accessed at the same time, then there are other reasons (such as the
config file) that make that not possible for now, and it seems like
it's an out-there use-case.

>> +     if (-1 == flock(lockfd, LOCK_EX)) {
>
> i guess flock() on the fd returned from the mtd device itself doesn't work ?

Again.. the thought it to be atomic across all accesses.  We want to
avoid the read / modify / write problems.

Thanks,
-Joe

^ permalink raw reply	[flat|nested] 124+ messages in thread

* [U-Boot] [PATCH v2 0/5] Cleanup fw_*env and a few common env
  2012-08-17 20:49                             ` [U-Boot] [PATCH 0/12] Add environment type checking and access control Joe Hershberger
                                                 ` (11 preceding siblings ...)
  2012-08-17 20:49                               ` [U-Boot] [PATCH 12/12] env: cosmetic: Consilidate the default env definition Joe Hershberger
@ 2012-10-03 19:38                               ` Joe Hershberger
  2012-10-03 19:38                                 ` [U-Boot] [PATCH v2 1/5] tools/env: Use a board-specific default env Joe Hershberger
                                                   ` (5 more replies)
  12 siblings, 6 replies; 124+ messages in thread
From: Joe Hershberger @ 2012-10-03 19:38 UTC (permalink / raw)
  To: u-boot

This is a gutted version of my previous env series in an effort to reduce the
risk to the release that is approaching shortly.

Changes in v2:
- Further simplified based Mike's comments

Joe Hershberger (5):
  tools/env: Use a board-specific default env
  tools/env: Remove unneeded complexity
  tools/env: Don't call env_init() in fw_getenv()
  tools/env: Serialize calls to fw_*env
  env: Check for NULL pointer in envmatch()

 common/cmd_nvedit.c     |  3 +++
 tools/env/Makefile      |  5 ++--
 tools/env/fw_env.c      | 66 +++++++++++++++++++++----------------------------
 tools/env/fw_env.h      | 19 ++++++++++++++
 tools/env/fw_env_main.c | 59 ++++++++++++++++++++++++++-----------------
 5 files changed, 90 insertions(+), 62 deletions(-)

-- 
1.7.11.5

^ permalink raw reply	[flat|nested] 124+ messages in thread

* [U-Boot] [PATCH v2 1/5] tools/env: Use a board-specific default env
  2012-10-03 19:38                               ` [U-Boot] [PATCH v2 0/5] Cleanup fw_*env and a few common env Joe Hershberger
@ 2012-10-03 19:38                                 ` Joe Hershberger
  2012-10-03 19:38                                 ` [U-Boot] [PATCH v2 2/5] tools/env: Remove unneeded complexity Joe Hershberger
                                                   ` (4 subsequent siblings)
  5 siblings, 0 replies; 124+ messages in thread
From: Joe Hershberger @ 2012-10-03 19:38 UTC (permalink / raw)
  To: u-boot

Originally added in aa701b94336b358798d676eef12a7b90bdac23f5

Before this patch, there was a hard-coded env that was used as default
if the env in flash is detected as invalid.  Now this tool (compiled
for a given board) will share the default env with the u-boot for the
board.

Fix include of config.h

Need to define "TEXT_BASE" when building the fw_env tool so that the
default env will be correct for environments which use it.

Define __ASSEMBLY__ when calling #include <config.h> so that we only
get #defines (all we're interested in).

Signed-off-by: Joe Hershberger <joe.hershberger@ni.com>
---

 tools/env/Makefile |  5 +++--
 tools/env/fw_env.c | 28 +++++++++++++---------------
 tools/env/fw_env.h | 19 +++++++++++++++++++
 3 files changed, 35 insertions(+), 17 deletions(-)

diff --git a/tools/env/Makefile b/tools/env/Makefile
index 07634bc..ab73c8c 100644
--- a/tools/env/Makefile
+++ b/tools/env/Makefile
@@ -24,13 +24,14 @@
 include $(TOPDIR)/config.mk
 
 HOSTSRCS := $(SRCTREE)/lib/crc32.c  fw_env.c  fw_env_main.c
-HEADERS	:= fw_env.h
+HEADERS	:= fw_env.h $(OBJTREE)/include/config.h
 
 # Compile for a hosted environment on the target
 HOSTCPPFLAGS  = -idirafter $(SRCTREE)/include \
 		-idirafter $(OBJTREE)/include2 \
 		-idirafter $(OBJTREE)/include \
-		-DUSE_HOSTCC
+		-DUSE_HOSTCC \
+		-DTEXT_BASE=$(TEXT_BASE)
 
 ifeq ($(MTD_VERSION),old)
 HOSTCPPFLAGS += -DMTD_OLD
diff --git a/tools/env/fw_env.c b/tools/env/fw_env.c
index 1a2c227..16073ea 100644
--- a/tools/env/fw_env.c
+++ b/tools/env/fw_env.c
@@ -45,8 +45,6 @@
 
 #include "fw_env.h"
 
-#include <config.h>
-
 #define WHITESPACE(c) ((c == '\t') || (c == ' '))
 
 #define min(x, y) ({				\
@@ -81,7 +79,7 @@ static int dev_current;
 #define ENVSECTORS(i) envdevices[(i)].env_sectors
 #define DEVTYPE(i)    envdevices[(i)].mtd_type
 
-#define CONFIG_ENV_SIZE ENVSIZE(dev_current)
+#define CUR_ENVSIZE ENVSIZE(dev_current)
 
 #define ENV_SIZE      getenvsize()
 
@@ -229,7 +227,7 @@ static int get_config (char *);
 #endif
 static inline ulong getenvsize (void)
 {
-	ulong rc = CONFIG_ENV_SIZE - sizeof (long);
+	ulong rc = CUR_ENVSIZE - sizeof(long);
 
 	if (HaveRedundEnv)
 		rc -= sizeof (char);
@@ -445,7 +443,7 @@ int fw_env_write(char *name, char *value)
 		++env;
 	/*
 	 * Overflow when:
-	 * "name" + "=" + "val" +"\0\0"  > CONFIG_ENV_SIZE - (env-environment)
+	 * "name" + "=" + "val" +"\0\0"  > CUR_ENVSIZE - (env-environment)
 	 */
 	len = strlen (name) + 2;
 	/* add '=' for first arg, ' ' for all others */
@@ -960,8 +958,8 @@ static int flash_write (int fd_current, int fd_target, int dev_target)
 	printf ("Writing new environment at 0x%lx on %s\n",
 		DEVOFFSET (dev_target), DEVNAME (dev_target));
 #endif
-	rc = flash_write_buf (dev_target, fd_target, environment.image,
-			      CONFIG_ENV_SIZE, DEVOFFSET (dev_target),
+	rc = flash_write_buf(dev_target, fd_target, environment.image,
+			      CUR_ENVSIZE, DEVOFFSET(dev_target),
 			      DEVTYPE(dev_target));
 	if (rc < 0)
 		return rc;
@@ -1000,10 +998,10 @@ static int flash_read (int fd)
 
 	DEVTYPE(dev_current) = mtdinfo.type;
 
-	rc = flash_read_buf (dev_current, fd, environment.image, CONFIG_ENV_SIZE,
+	rc = flash_read_buf(dev_current, fd, environment.image, CUR_ENVSIZE,
 			     DEVOFFSET (dev_current), mtdinfo.type);
 
-	return (rc != CONFIG_ENV_SIZE) ? -1 : 0;
+	return (rc != CUR_ENVSIZE) ? -1 : 0;
 }
 
 static int flash_io (int mode)
@@ -1100,11 +1098,11 @@ int fw_env_open(void)
 	if (parse_config ())		/* should fill envdevices */
 		return -1;
 
-	addr0 = calloc (1, CONFIG_ENV_SIZE);
+	addr0 = calloc(1, CUR_ENVSIZE);
 	if (addr0 == NULL) {
-		fprintf (stderr,
+		fprintf(stderr,
 			"Not enough memory for environment (%ld bytes)\n",
-			CONFIG_ENV_SIZE);
+			CUR_ENVSIZE);
 		return -1;
 	}
 
@@ -1139,11 +1137,11 @@ int fw_env_open(void)
 		flag0 = *environment.flags;
 
 		dev_current = 1;
-		addr1 = calloc (1, CONFIG_ENV_SIZE);
+		addr1 = calloc(1, CUR_ENVSIZE);
 		if (addr1 == NULL) {
-			fprintf (stderr,
+			fprintf(stderr,
 				"Not enough memory for environment (%ld bytes)\n",
-				CONFIG_ENV_SIZE);
+				CUR_ENVSIZE);
 			return -1;
 		}
 		redundant = addr1;
diff --git a/tools/env/fw_env.h b/tools/env/fw_env.h
index ad32446..a1a6807 100644
--- a/tools/env/fw_env.h
+++ b/tools/env/fw_env.h
@@ -21,6 +21,15 @@
  * MA 02111-1307 USA
  */
 
+/* Pull in the current config to define the default environment */
+#ifndef __ASSEMBLY__
+#define __ASSEMBLY__ /* get only #defines from config.h */
+#include <config.h>
+#undef	__ASSEMBLY__
+#else
+#include <config.h>
+#endif
+
 /*
  * To build the utility with the static configuration
  * comment out the next line.
@@ -29,6 +38,7 @@
  */
 #define CONFIG_FILE     "/etc/fw_env.config"
 
+#ifndef CONFIG_FILE
 #define HAVE_REDUND /* For systems with 2 env sectors */
 #define DEVICE1_NAME      "/dev/mtd1"
 #define DEVICE2_NAME      "/dev/mtd2"
@@ -40,14 +50,23 @@
 #define ENV2_SIZE         0x4000
 #define DEVICE2_ESIZE     0x4000
 #define DEVICE2_ENVSECTORS     2
+#endif
 
+#ifndef CONFIG_BAUDRATE
 #define CONFIG_BAUDRATE		115200
+#endif
+
+#ifndef CONFIG_BOOTDELAY
 #define CONFIG_BOOTDELAY	5	/* autoboot after 5 seconds	*/
+#endif
+
+#ifndef CONFIG_BOOTCOMMAND
 #define CONFIG_BOOTCOMMAND							\
 	"bootp; "								\
 	"setenv bootargs root=/dev/nfs nfsroot=${serverip}:${rootpath} "	\
 	"ip=${ipaddr}:${serverip}:${gatewayip}:${netmask}:${hostname}::off; "	\
 	"bootm"
+#endif
 
 extern int   fw_printenv(int argc, char *argv[]);
 extern char *fw_getenv  (char *name);
-- 
1.7.11.5

^ permalink raw reply related	[flat|nested] 124+ messages in thread

* [U-Boot] [PATCH v2 2/5] tools/env: Remove unneeded complexity
  2012-10-03 19:38                               ` [U-Boot] [PATCH v2 0/5] Cleanup fw_*env and a few common env Joe Hershberger
  2012-10-03 19:38                                 ` [U-Boot] [PATCH v2 1/5] tools/env: Use a board-specific default env Joe Hershberger
@ 2012-10-03 19:38                                 ` Joe Hershberger
  2012-10-03 19:38                                 ` [U-Boot] [PATCH v2 3/5] tools/env: Don't call env_init() in fw_getenv() Joe Hershberger
                                                   ` (3 subsequent siblings)
  5 siblings, 0 replies; 124+ messages in thread
From: Joe Hershberger @ 2012-10-03 19:38 UTC (permalink / raw)
  To: u-boot

The length included the name length, and then it was subtracted back
out on each use.  Now we don't include it in the first place.  Also
realloc as we process arguments and eliminate memset.  Use memcpy
instead of manually copying each byte.

Signed-off-by: Joe Hershberger <joe.hershberger@ni.com>
---
Changes in v2:
- Further simplified based Mike's comments

 tools/env/fw_env.c | 33 +++++++++++++--------------------
 1 file changed, 13 insertions(+), 20 deletions(-)

diff --git a/tools/env/fw_env.c b/tools/env/fw_env.c
index 16073ea..af879f1 100644
--- a/tools/env/fw_env.c
+++ b/tools/env/fw_env.c
@@ -481,7 +481,6 @@ int fw_setenv(int argc, char *argv[])
 	int i, len;
 	char *name;
 	char *value = NULL;
-	char *tmpval = NULL;
 
 	if (argc < 2) {
 		errno = EINVAL;
@@ -495,34 +494,28 @@ int fw_setenv(int argc, char *argv[])
 
 	name = argv[1];
 
-	len = strlen(name) + 2;
-	for (i = 2; i < argc; ++i)
-		len += strlen(argv[i]) + 1;
-
-	/* Allocate enough place to the data string */
+	len = 0;
 	for (i = 2; i < argc; ++i) {
 		char *val = argv[i];
+		size_t val_len = strlen(val);
+
+		value = realloc(value, len + val_len + 1);
 		if (!value) {
-			value = (char *)malloc(len - strlen(name));
-			if (!value) {
-				fprintf(stderr,
+			fprintf(stderr,
 				"Cannot malloc %zu bytes: %s\n",
-				len - strlen(name), strerror(errno));
-				return -1;
-			}
-			memset(value, 0, len - strlen(name));
-			tmpval = value;
+				len, strerror(errno));
+			return -1;
 		}
-		if (i != 2)
-			*tmpval++ = ' ';
-		while (*val != '\0')
-			*tmpval++ = *val++;
+
+		memcpy(value + len, val, val_len);
+		len += val_len;
+		value[len++] = ' ';
 	}
+	value[len - 1] = '\0';
 
 	fw_env_write(name, value);
 
-	if (value)
-		free(value);
+	free(value);
 
 	return fw_env_close();
 }
-- 
1.7.11.5

^ permalink raw reply related	[flat|nested] 124+ messages in thread

* [U-Boot] [PATCH v2 3/5] tools/env: Don't call env_init() in fw_getenv()
  2012-10-03 19:38                               ` [U-Boot] [PATCH v2 0/5] Cleanup fw_*env and a few common env Joe Hershberger
  2012-10-03 19:38                                 ` [U-Boot] [PATCH v2 1/5] tools/env: Use a board-specific default env Joe Hershberger
  2012-10-03 19:38                                 ` [U-Boot] [PATCH v2 2/5] tools/env: Remove unneeded complexity Joe Hershberger
@ 2012-10-03 19:38                                 ` Joe Hershberger
  2012-10-03 19:38                                 ` [U-Boot] [PATCH v2 4/5] tools/env: Serialize calls to fw_*env Joe Hershberger
                                                   ` (2 subsequent siblings)
  5 siblings, 0 replies; 124+ messages in thread
From: Joe Hershberger @ 2012-10-03 19:38 UTC (permalink / raw)
  To: u-boot

We will only call fw_getenv when the env has already been initialized.

Signed-off-by: Joe Hershberger <joe.hershberger@ni.com>
---

 tools/env/fw_env.c | 3 ---
 1 file changed, 3 deletions(-)

diff --git a/tools/env/fw_env.c b/tools/env/fw_env.c
index af879f1..f883804 100644
--- a/tools/env/fw_env.c
+++ b/tools/env/fw_env.c
@@ -258,9 +258,6 @@ char *fw_getenv (char *name)
 {
 	char *env, *nxt;
 
-	if (fw_env_open())
-		return NULL;
-
 	for (env = environment.data; *env; env = nxt + 1) {
 		char *val;
 
-- 
1.7.11.5

^ permalink raw reply related	[flat|nested] 124+ messages in thread

* [U-Boot] [PATCH v2 4/5] tools/env: Serialize calls to fw_*env
  2012-10-03 19:38                               ` [U-Boot] [PATCH v2 0/5] Cleanup fw_*env and a few common env Joe Hershberger
                                                   ` (2 preceding siblings ...)
  2012-10-03 19:38                                 ` [U-Boot] [PATCH v2 3/5] tools/env: Don't call env_init() in fw_getenv() Joe Hershberger
@ 2012-10-03 19:38                                 ` Joe Hershberger
  2012-10-03 23:24                                   ` uboot at lukaperkov.net
  2012-10-03 19:38                                 ` [U-Boot] [PATCH v2 5/5] env: Check for NULL pointer in envmatch() Joe Hershberger
  2012-10-09 17:13                                 ` [U-Boot] [PATCH v2 0/5] Cleanup fw_*env and a few common env Tom Rini
  5 siblings, 1 reply; 124+ messages in thread
From: Joe Hershberger @ 2012-10-03 19:38 UTC (permalink / raw)
  To: u-boot

Use a lock file at /var/lock/fw_printenv.lock.
Avoids seriously confusing the MTD driver.

Signed-off-by: Joe Hershberger <joe.hershberger@ni.com>
---

 tools/env/fw_env_main.c | 59 +++++++++++++++++++++++++++++++------------------
 1 file changed, 37 insertions(+), 22 deletions(-)

diff --git a/tools/env/fw_env_main.c b/tools/env/fw_env_main.c
index c654057..c855f4c 100644
--- a/tools/env/fw_env_main.c
+++ b/tools/env/fw_env_main.c
@@ -39,10 +39,13 @@
  *		  variable "name"
  */
 
+#include <fcntl.h>
+#include <getopt.h>
 #include <stdio.h>
 #include <string.h>
 #include <stdlib.h>
-#include <getopt.h>
+#include <sys/file.h>
+#include <unistd.h>
 #include "fw_env.h"
 
 #define	CMD_PRINTENV	"fw_printenv"
@@ -81,13 +84,27 @@ void usage(void)
 	);
 }
 
-int
-main(int argc, char *argv[])
+int main(int argc, char *argv[])
 {
 	char *p;
 	char *cmdname = *argv;
 	char *script_file = NULL;
 	int c;
+	const char *lockname = "/var/lock/" CMD_PRINTENV ".lock";
+	int lockfd = -1;
+	int retval = EXIT_SUCCESS;
+
+	lockfd = open(lockname, O_WRONLY | O_CREAT | O_TRUNC);
+	if (-1 == lockfd) {
+		fprintf(stderr, "Error opening lock file %s\n", lockname);
+		return EXIT_FAILURE;
+	}
+
+	if (-1 == flock(lockfd, LOCK_EX)) {
+		fprintf(stderr, "Error locking file %s\n", lockname);
+		close(lockfd);
+		return EXIT_FAILURE;
+	}
 
 	if ((p = strrchr (cmdname, '/')) != NULL) {
 		cmdname = p + 1;
@@ -104,38 +121,36 @@ main(int argc, char *argv[])
 			break;
 		case 'h':
 			usage();
-			return EXIT_SUCCESS;
+			goto exit;
 		default: /* '?' */
 			fprintf(stderr, "Try `%s --help' for more information."
 				"\n", cmdname);
-			return EXIT_FAILURE;
+			retval = EXIT_FAILURE;
+			goto exit;
 		}
 	}
 
-
 	if (strcmp(cmdname, CMD_PRINTENV) == 0) {
-
-		if (fw_printenv (argc, argv) != 0)
-			return EXIT_FAILURE;
-
-		return EXIT_SUCCESS;
-
+		if (fw_printenv(argc, argv) != 0)
+			retval = EXIT_FAILURE;
 	} else if (strcmp(cmdname, CMD_SETENV) == 0) {
 		if (!script_file) {
 			if (fw_setenv(argc, argv) != 0)
-				return EXIT_FAILURE;
+				retval = EXIT_FAILURE;
 		} else {
 			if (fw_parse_script(script_file) != 0)
-				return EXIT_FAILURE;
+				retval = EXIT_FAILURE;
 		}
-
-		return EXIT_SUCCESS;
-
+	} else {
+		fprintf(stderr,
+			"Identity crisis - may be called as `" CMD_PRINTENV
+			"' or as `" CMD_SETENV "' but not as `%s'\n",
+			cmdname);
+		retval = EXIT_FAILURE;
 	}
 
-	fprintf (stderr,
-		"Identity crisis - may be called as `" CMD_PRINTENV
-		"' or as `" CMD_SETENV "' but not as `%s'\n",
-		cmdname);
-	return EXIT_FAILURE;
+exit:
+	flock(lockfd, LOCK_UN);
+	close(lockfd);
+	return retval;
 }
-- 
1.7.11.5

^ permalink raw reply related	[flat|nested] 124+ messages in thread

* [U-Boot] [PATCH v2 5/5] env: Check for NULL pointer in envmatch()
  2012-10-03 19:38                               ` [U-Boot] [PATCH v2 0/5] Cleanup fw_*env and a few common env Joe Hershberger
                                                   ` (3 preceding siblings ...)
  2012-10-03 19:38                                 ` [U-Boot] [PATCH v2 4/5] tools/env: Serialize calls to fw_*env Joe Hershberger
@ 2012-10-03 19:38                                 ` Joe Hershberger
  2012-10-09 17:13                                 ` [U-Boot] [PATCH v2 0/5] Cleanup fw_*env and a few common env Tom Rini
  5 siblings, 0 replies; 124+ messages in thread
From: Joe Hershberger @ 2012-10-03 19:38 UTC (permalink / raw)
  To: u-boot

If the pointer passed into envmatch() is NULL, return -1 instead of
crashing.

Signed-off-by: Joe Hershberger <joe.hershberger@ni.com>
---

 common/cmd_nvedit.c | 3 +++
 tools/env/fw_env.c  | 2 ++
 2 files changed, 5 insertions(+)

diff --git a/common/cmd_nvedit.c b/common/cmd_nvedit.c
index 3474bc6..5a28dee 100644
--- a/common/cmd_nvedit.c
+++ b/common/cmd_nvedit.c
@@ -646,6 +646,9 @@ U_BOOT_CMD(
  */
 int envmatch(uchar *s1, int i2)
 {
+	if (s1 == NULL)
+		return -1;
+
 	while (*s1 == env_get_char(i2++))
 		if (*s1++ == '=')
 			return i2;
diff --git a/tools/env/fw_env.c b/tools/env/fw_env.c
index f883804..ed56ba0 100644
--- a/tools/env/fw_env.c
+++ b/tools/env/fw_env.c
@@ -1060,6 +1060,8 @@ exit:
 
 static char *envmatch (char * s1, char * s2)
 {
+	if (s1 == NULL || s2 == NULL)
+		return NULL;
 
 	while (*s1 == *s2++)
 		if (*s1++ == '=')
-- 
1.7.11.5

^ permalink raw reply related	[flat|nested] 124+ messages in thread

* [U-Boot] [PATCH v2 4/5] tools/env: Serialize calls to fw_*env
  2012-10-03 19:38                                 ` [U-Boot] [PATCH v2 4/5] tools/env: Serialize calls to fw_*env Joe Hershberger
@ 2012-10-03 23:24                                   ` uboot at lukaperkov.net
  2012-10-04 18:31                                     ` [U-Boot] [PATCH] tools: Add a README note about fw_printenv lock file Joe Hershberger
  0 siblings, 1 reply; 124+ messages in thread
From: uboot at lukaperkov.net @ 2012-10-03 23:24 UTC (permalink / raw)
  To: u-boot

On Wed, Oct 03, 2012 at 02:38:49PM -0500, Joe Hershberger wrote:
> Use a lock file at /var/lock/fw_printenv.lock.
> Avoids seriously confusing the MTD driver.
> 
> Signed-off-by: Joe Hershberger <joe.hershberger@ni.com>
> ---
> 
>  tools/env/fw_env_main.c | 59 +++++++++++++++++++++++++++++++------------------
>  1 file changed, 37 insertions(+), 22 deletions(-)

I thing we should document usage and location of lock file in tools/env/README. 

Luka

^ permalink raw reply	[flat|nested] 124+ messages in thread

* [U-Boot] [PATCH] tools: Add a README note about fw_printenv lock file
  2012-10-03 23:24                                   ` uboot at lukaperkov.net
@ 2012-10-04 18:31                                     ` Joe Hershberger
  0 siblings, 0 replies; 124+ messages in thread
From: Joe Hershberger @ 2012-10-04 18:31 UTC (permalink / raw)
  To: u-boot

Add a mention of the lock file to the README for the fw_printenv tool.

Signed-off-by: Joe Hershberger <joe.hershberger@ni.com>
Reported-by: Luka Perkov <uboot@lukaperkov.net>
---
This patch is independent of the series, but should be applied afterward

 tools/env/README | 4 ++++
 1 file changed, 4 insertions(+)

diff --git a/tools/env/README b/tools/env/README
index 3f0d77e..df020e4 100644
--- a/tools/env/README
+++ b/tools/env/README
@@ -55,3 +55,7 @@ partition where the environment resides.
 DEVICEx_ENVSECTORS defines the number of sectors that may be used for
 this environment instance. On NAND this is used to limit the range
 within which bad blocks are skipped, on NOR it is not used.
+
+To prevent losing changes to the environment and to prevent confusing the MTD
+drivers, a lock file at /var/lock/fw_printenv.lock is used to serialize access
+to the environment.
-- 
1.7.11.5

^ permalink raw reply related	[flat|nested] 124+ messages in thread

* [U-Boot] [PATCH v2 0/5] Cleanup fw_*env and a few common env
  2012-10-03 19:38                               ` [U-Boot] [PATCH v2 0/5] Cleanup fw_*env and a few common env Joe Hershberger
                                                   ` (4 preceding siblings ...)
  2012-10-03 19:38                                 ` [U-Boot] [PATCH v2 5/5] env: Check for NULL pointer in envmatch() Joe Hershberger
@ 2012-10-09 17:13                                 ` Tom Rini
  5 siblings, 0 replies; 124+ messages in thread
From: Tom Rini @ 2012-10-09 17:13 UTC (permalink / raw)
  To: u-boot

On Wed, Oct 03, 2012 at 02:38:45PM -0500, Joe Hershberger wrote:

> This is a gutted version of my previous env series in an effort to reduce the
> risk to the release that is approaching shortly.
> 
> Changes in v2:
> - Further simplified based Mike's comments
> 
> Joe Hershberger (5):
>   tools/env: Use a board-specific default env
>   tools/env: Remove unneeded complexity
>   tools/env: Don't call env_init() in fw_getenv()
>   tools/env: Serialize calls to fw_*env
>   env: Check for NULL pointer in envmatch()
> 
>  common/cmd_nvedit.c     |  3 +++
>  tools/env/Makefile      |  5 ++--
>  tools/env/fw_env.c      | 66 +++++++++++++++++++++----------------------------
>  tools/env/fw_env.h      | 19 ++++++++++++++
>  tools/env/fw_env_main.c | 59 ++++++++++++++++++++++++++-----------------
>  5 files changed, 90 insertions(+), 62 deletions(-)

This, and the follow up README have been applied to u-boot/next, thanks!

-- 
Tom
-------------- next part --------------
A non-text attachment was scrubbed...
Name: not available
Type: application/pgp-signature
Size: 836 bytes
Desc: Digital signature
URL: <http://lists.denx.de/pipermail/u-boot/attachments/20121009/e92c473a/attachment.pgp>

^ permalink raw reply	[flat|nested] 124+ messages in thread

* [U-Boot] [PATCH v3 0/18] Add environment call-back and flags capability
  2012-09-14 18:42                                     ` Wolfgang Denk
@ 2012-11-01 16:39                                       ` Joe Hershberger
  2012-11-01 16:39                                         ` [U-Boot] [PATCH v3 01/18] Make linux kernel string funcs available to tools Joe Hershberger
                                                           ` (19 more replies)
  0 siblings, 20 replies; 124+ messages in thread
From: Joe Hershberger @ 2012-11-01 16:39 UTC (permalink / raw)
  To: u-boot


When a variable with a registered callback is inserted, deleted, or
overwritten the callback is called and gives the system an opportunity
to do something in response to the change.  It also has the opportunuty
to reject the change by returning non-zero.

The flags on variables can control their type as well as their allowed
access.

        The format of the list is:
                type_attribute = [s|d|x|b|i|m]
                attributes = type_attribute
                entry = variable_name[:attributes]
                list = entry[,list]

        The type attributes are:
                s - String (default)
                d - Decimal
                x - Hexadecimal
                b - Boolean ([1yYtT|0nNfF])
                i - IP address
                m - MAC address

        The access attributes are:
                a - Any (default)
                r - Read-only
                o - Write-once
                c - Change-default

Changes in v3:
- Rebase onto Gerlando Falauto's env patches
- Refactor himport_r() and hsearch_r()'s parameters
- Split hdelete_r() into the core delete and the validation before
delete
- Delete vars on failed insertion
- Use Marek's linker lists instead of implementing it directly
- Rebase onto latest master
- Add flags parameter to callbacks
- Implement reverse search in env_attr_lookup()
- Fix space skipping in env_attr_lookup()
- All errors coming back from hsearch_r() are no longer fatal.  Don't
abort import on failed ENTER action.
- Removed checkpatch.pl warning

Changes in v2:
- Added much-needed documentation
- Factored out prevch and nextch in env_attr_lookup()

Joe Hershberger (18):
  Make linux kernel string funcs available to tools
  env: Refactor do_apply to a flag
  env: Consolidate common code in hsearch_r()
  env: Refactor apply into change_ok
  env: Use getenv_yesno() more generally
  env: Hide '.' variables in env print by default
  env: Add support for callbacks to environment vars
  env: Add a command to view callbacks
  env: Add a bootfile env handler
  env: Add a baudrate env handler
  env: Add a loadaddr env handler
  env: Add a console env handler
  env: Add a silent env handler
  env: Add environment variable flags
  tools/env: Add environment variable flags support
  env: Add a command to display details about env flags
  env: Add support for access control to .flags
  env: Handle write-once ethaddr and serial# generically

 README                          |  80 ++++++
 arch/arm/lib/board.c            |   4 +-
 arch/m68k/lib/board.c           |   3 +-
 arch/microblaze/lib/board.c     |   4 +-
 arch/powerpc/cpu/mpc85xx/mp.c   |   4 +-
 arch/powerpc/lib/board.c        |   9 +-
 arch/sparc/lib/board.c          |   3 +-
 board/Marvell/db64360/db64360.c |  10 +-
 board/Marvell/db64460/db64460.c |  10 +-
 board/esd/cpci750/cpci750.c     |  10 +-
 board/esd/pmc440/cmd_pmc440.c   |   2 +-
 board/gw8260/gw8260.c           |  10 +-
 board/prodrive/p3mx/p3mx.c      |  10 +-
 common/Makefile                 |   6 +
 common/cmd_nvedit.c             | 337 ++++++++++++------------
 common/console.c                |  67 +++++
 common/env_attr.c               | 229 +++++++++++++++++
 common/env_callback.c           | 132 ++++++++++
 common/env_common.c             |  60 +++--
 common/env_dataflash.c          |   2 +-
 common/env_eeprom.c             |   2 +-
 common/env_fat.c                |   2 +-
 common/env_flags.c              | 549 ++++++++++++++++++++++++++++++++++++++++
 common/env_flash.c              |   4 +-
 common/env_mmc.c                |   2 +-
 common/env_nand.c               |   4 +-
 common/env_nvram.c              |   2 +-
 common/env_onenand.c            |   2 +-
 common/env_sf.c                 |   4 +-
 common/image.c                  |  21 +-
 doc/README.silent               |  14 +-
 drivers/serial/serial.c         |  70 +++++
 include/common.h                |   5 +
 include/env_attr.h              |  55 ++++
 include/env_callback.h          |  75 ++++++
 include/env_default.h           |   8 +
 include/env_flags.h             | 172 +++++++++++++
 include/environment.h           |  15 +-
 include/image.h                 |   1 -
 include/linux/linux_string.h    |   8 +
 include/linux/string.h          |   5 +-
 include/search.h                |  37 ++-
 lib/Makefile                    |   1 +
 lib/hashtable.c                 | 244 ++++++++++++------
 lib/linux_string.c              |  51 ++++
 lib/string.c                    |  39 ---
 net/net.c                       |  49 ++--
 tools/env/Makefile              |   3 +
 tools/env/fw_env.c              |  92 +++++--
 49 files changed, 2093 insertions(+), 435 deletions(-)
 create mode 100644 common/env_attr.c
 create mode 100644 common/env_callback.c
 create mode 100644 common/env_flags.c
 create mode 100644 include/env_attr.h
 create mode 100644 include/env_callback.h
 create mode 100644 include/env_flags.h
 create mode 100644 include/linux/linux_string.h
 create mode 100644 lib/linux_string.c

-- 
1.7.11.5

^ permalink raw reply	[flat|nested] 124+ messages in thread

* [U-Boot] [PATCH v3 01/18] Make linux kernel string funcs available to tools
  2012-11-01 16:39                                       ` [U-Boot] [PATCH v3 0/18] Add environment call-back and flags capability Joe Hershberger
@ 2012-11-01 16:39                                         ` Joe Hershberger
  2012-11-01 16:39                                         ` [U-Boot] [PATCH v3 02/18] env: Refactor do_apply to a flag Joe Hershberger
                                                           ` (18 subsequent siblings)
  19 siblings, 0 replies; 124+ messages in thread
From: Joe Hershberger @ 2012-11-01 16:39 UTC (permalink / raw)
  To: u-boot

isspace() and strim() are not in the typical user-mode string.h, so
put them in a separate compilation unit so that they can be built into
tools that need them independent of the other common string functions.

This allows code shared by u-boot and the linux user-mode tools to link.

Signed-off-by: Joe Hershberger <joe.hershberger@ni.com>
---

 include/linux/linux_string.h |  8 +++++++
 include/linux/string.h       |  5 +----
 lib/Makefile                 |  1 +
 lib/linux_string.c           | 51 ++++++++++++++++++++++++++++++++++++++++++++
 lib/string.c                 | 39 ---------------------------------
 5 files changed, 61 insertions(+), 43 deletions(-)
 create mode 100644 include/linux/linux_string.h
 create mode 100644 lib/linux_string.c

diff --git a/include/linux/linux_string.h b/include/linux/linux_string.h
new file mode 100644
index 0000000..192b4c9
--- /dev/null
+++ b/include/linux/linux_string.h
@@ -0,0 +1,8 @@
+#ifndef _LINUX_LINUX_STRING_H_
+#define _LINUX_LINUX_STRING_H_
+
+extern char * skip_spaces(const char *);
+
+extern char *strim(char *);
+
+#endif
diff --git a/include/linux/string.h b/include/linux/string.h
index 9a8cbc2..2a6e52f 100644
--- a/include/linux/string.h
+++ b/include/linux/string.h
@@ -47,10 +47,7 @@ extern char * strchr(const char *,int);
 #ifndef __HAVE_ARCH_STRRCHR
 extern char * strrchr(const char *,int);
 #endif
-extern char * skip_spaces(const char *);
-
-extern char *strim(char *);
-
+#include <linux/linux_string.h>
 #ifndef __HAVE_ARCH_STRSTR
 extern char * strstr(const char *,const char *);
 #endif
diff --git a/lib/Makefile b/lib/Makefile
index e44e045..5652986 100644
--- a/lib/Makefile
+++ b/lib/Makefile
@@ -68,6 +68,7 @@ endif
 COBJS-y += crc32.o
 COBJS-y += ctype.o
 COBJS-y += div64.o
+COBJS-y += linux_string.o
 COBJS-y += string.o
 COBJS-y += time.o
 COBJS-$(CONFIG_BOOTP_PXE) += uuid.o
diff --git a/lib/linux_string.c b/lib/linux_string.c
new file mode 100644
index 0000000..d5a5e08
--- /dev/null
+++ b/lib/linux_string.c
@@ -0,0 +1,51 @@
+/*
+ *  linux/lib/string.c
+ *
+ *  Copyright (C) 1991, 1992  Linus Torvalds
+ */
+
+#ifdef USE_HOSTCC
+#include <stdio.h>
+#endif
+
+#include <linux/ctype.h>
+#include <linux/string.h>
+
+/**
+ * skip_spaces - Removes leading whitespace from @str.
+ * @str: The string to be stripped.
+ *
+ * Returns a pointer to the first non-whitespace character in @str.
+ */
+char *skip_spaces(const char *str)
+{
+	while (isspace(*str))
+		++str;
+	return (char *)str;
+}
+
+/**
+ * strim - Removes leading and trailing whitespace from @s.
+ * @s: The string to be stripped.
+ *
+ * Note that the first trailing whitespace is replaced with a %NUL-terminator
+ * in the given string @s. Returns a pointer to the first non-whitespace
+ * character in @s.
+ */
+char *strim(char *s)
+{
+	size_t size;
+	char *end;
+
+	s = skip_spaces(s);
+	size = strlen(s);
+	if (!size)
+		return s;
+
+	end = s + size - 1;
+	while (end >= s && isspace(*end))
+		end--;
+	*(end + 1) = '\0';
+
+	return s;
+}
diff --git a/lib/string.c b/lib/string.c
index c3ad055..2c4f0ec 100644
--- a/lib/string.c
+++ b/lib/string.c
@@ -214,45 +214,6 @@ char * strrchr(const char * s, int c)
 }
 #endif
 
-
-/**
- * skip_spaces - Removes leading whitespace from @str.
- * @str: The string to be stripped.
- *
- * Returns a pointer to the first non-whitespace character in @str.
- */
-char *skip_spaces(const char *str)
-{
-	while (isspace(*str))
-		++str;
-	return (char *)str;
-}
-
-/**
- * strim - Removes leading and trailing whitespace from @s.
- * @s: The string to be stripped.
- *
- * Note that the first trailing whitespace is replaced with a %NUL-terminator
- * in the given string @s. Returns a pointer to the first non-whitespace
- * character in @s.
- */
-char *strim(char *s)
-{
-	size_t size;
-	char *end;
-
-	s = skip_spaces(s);
-	size = strlen(s);
-	if (!size)
-		return s;
-
-	end = s + size - 1;
-	while (end >= s && isspace(*end))
-		end--;
-	*(end + 1) = '\0';
-
-	return s;
-}
 #ifndef __HAVE_ARCH_STRLEN
 /**
  * strlen - Find the length of a string
-- 
1.7.11.5

^ permalink raw reply related	[flat|nested] 124+ messages in thread

* [U-Boot] [PATCH v3 02/18] env: Refactor do_apply to a flag
  2012-11-01 16:39                                       ` [U-Boot] [PATCH v3 0/18] Add environment call-back and flags capability Joe Hershberger
  2012-11-01 16:39                                         ` [U-Boot] [PATCH v3 01/18] Make linux kernel string funcs available to tools Joe Hershberger
@ 2012-11-01 16:39                                         ` Joe Hershberger
  2012-11-01 16:39                                         ` [U-Boot] [PATCH v3 03/18] env: Consolidate common code in hsearch_r() Joe Hershberger
                                                           ` (17 subsequent siblings)
  19 siblings, 0 replies; 124+ messages in thread
From: Joe Hershberger @ 2012-11-01 16:39 UTC (permalink / raw)
  To: u-boot

Use a flag in hsearch_r for insert mode passed from import to allow the
behavior be different based on use.

Signed-off-by: Joe Hershberger <joe.hershberger@ni.com>
---
Changes in v3:
- Rebase onto Gerlando Falauto's env patches
- Refactor himport_r() and hsearch_r()'s parameters

 common/cmd_nvedit.c | 17 ++++++++---------
 common/env_common.c | 26 ++++++++------------------
 include/search.h    | 15 ++++++++-------
 lib/hashtable.c     | 37 ++++++++++++++++++++-----------------
 4 files changed, 44 insertions(+), 51 deletions(-)

diff --git a/common/cmd_nvedit.c b/common/cmd_nvedit.c
index 68c38f4..4820008 100644
--- a/common/cmd_nvedit.c
+++ b/common/cmd_nvedit.c
@@ -116,7 +116,7 @@ static int env_print(char *name)
 
 		e.key = name;
 		e.data = NULL;
-		hsearch_r(e, FIND, &ep, &env_htab);
+		hsearch_r(e, FIND, &ep, &env_htab, 0);
 		if (ep == NULL)
 			return 0;
 		len = printf("%s=%s\n", ep->key, ep->data);
@@ -343,20 +343,19 @@ int _do_env_set(int flag, int argc, char * const argv[])
 	 */
 	e.key = name;
 	e.data = NULL;
-	hsearch_r(e, FIND, &ep, &env_htab);
+	hsearch_r(e, FIND, &ep, &env_htab, 0);
 
 	/*
-	 * Perform requested checks. Notice how since we are overwriting
-	 * a single variable, we need to set H_NOCLEAR
+	 * Perform requested checks.
 	 */
-	if (env_check_apply(name, ep ? ep->data : NULL, value, H_NOCLEAR)) {
+	if (env_check_apply(name, ep ? ep->data : NULL, value, 0)) {
 		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, 0);
+		int rc = hdelete_r(name, &env_htab, H_INTERACTIVE);
 		return !rc;
 	}
 
@@ -383,7 +382,7 @@ int _do_env_set(int flag, int argc, char * const argv[])
 
 	e.key	= name;
 	e.data	= value;
-	hsearch_r(e, ENTER, &ep, &env_htab);
+	hsearch_r(e, ENTER, &ep, &env_htab, H_INTERACTIVE);
 	free(value);
 	if (!ep) {
 		printf("## Error inserting \"%s\" variable, errno=%d\n",
@@ -550,7 +549,7 @@ char *getenv(const char *name)
 
 		e.key	= name;
 		e.data	= NULL;
-		hsearch_r(e, FIND, &ep, &env_htab);
+		hsearch_r(e, FIND, &ep, &env_htab, 0);
 
 		return ep ? ep->data : NULL;
 	}
@@ -948,7 +947,7 @@ static int do_env_import(cmd_tbl_t *cmdtp, int flag,
 	}
 
 	if (himport_r(&env_htab, addr, size, sep, del ? 0 : H_NOCLEAR,
-			0, NULL, 0 /* do_apply */) == 0) {
+			0, NULL) == 0) {
 		error("Environment import failed: errno = %d\n", errno);
 		return 1;
 	}
diff --git a/common/env_common.c b/common/env_common.c
index 3d3cb70..f22f5b9 100644
--- a/common/env_common.c
+++ b/common/env_common.c
@@ -83,11 +83,8 @@ 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
-	 */
-	int do_apply = 0;
+	int flags = 0;
+
 	if (sizeof(default_environment) > ENV_SIZE) {
 		puts("*** Error - default environment is too large\n\n");
 		return;
@@ -99,14 +96,7 @@ 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 check every single
-			 * variable and apply changes to the system
-			 * right away (e.g. baudrate, console).
-			 */
-			do_apply = 1;
+			flags = H_INTERACTIVE;
 			puts(s);
 		}
 	} else {
@@ -114,8 +104,8 @@ void set_default_env(const char *s)
 	}
 
 	if (himport_r(&env_htab, (char *)default_environment,
-			sizeof(default_environment), '\0', 0,
-			0, NULL, do_apply) == 0)
+			sizeof(default_environment), '\0', flags,
+			0, NULL) == 0)
 		error("Environment import failed: errno = %d\n", errno);
 
 	gd->flags |= GD_FLG_ENV_READY;
@@ -130,8 +120,8 @@ int set_default_vars(int nvars, char * const vars[])
 	 * (and use \0 as a separator)
 	 */
 	return himport_r(&env_htab, (const char *)default_environment,
-				sizeof(default_environment), '\0', H_NOCLEAR,
-				nvars, vars, 1 /* do_apply */);
+				sizeof(default_environment), '\0',
+				H_NOCLEAR | H_INTERACTIVE, nvars, vars);
 }
 
 #ifndef CONFIG_SPL_BUILD
@@ -155,7 +145,7 @@ int env_import(const char *buf, int check)
 	}
 
 	if (himport_r(&env_htab, (char *)ep->data, ENV_SIZE, '\0', 0,
-			0, NULL, 0 /* do_apply */)) {
+			0, NULL)) {
 		gd->flags |= GD_FLG_ENV_READY;
 		return 1;
 	}
diff --git a/include/search.h b/include/search.h
index 93e1cbc..f5165b0 100644
--- a/include/search.h
+++ b/include/search.h
@@ -73,7 +73,7 @@ struct hsearch_data {
 extern int hcreate_r(size_t __nel, struct hsearch_data *__htab);
 
 /* Destroy current internal hashing table.  */
-extern void hdestroy_r(struct hsearch_data *__htab, int do_apply);
+extern void hdestroy_r(struct hsearch_data *__htab);
 
 /*
  * Search for entry matching ITEM.key in internal hash table.  If
@@ -82,7 +82,7 @@ extern void hdestroy_r(struct hsearch_data *__htab, int do_apply);
  * ITEM.data.
  * */
 extern int hsearch_r(ENTRY __item, ACTION __action, ENTRY ** __retval,
-		     struct hsearch_data *__htab);
+		     struct hsearch_data *__htab, int __flag);
 
 /*
  * Search for an entry matching `MATCH'.  Otherwise, Same semantics
@@ -99,7 +99,7 @@ extern int hstrstr_r(const char *__match, int __last_idx, ENTRY ** __retval,
 
 /* Search and delete entry matching ITEM.key in internal hash table. */
 extern int hdelete_r(const char *__key, struct hsearch_data *__htab,
-			int do_apply);
+		     int __flag);
 
 extern ssize_t hexport_r(struct hsearch_data *__htab,
 		     const char __sep, char **__resp, size_t __size,
@@ -113,10 +113,11 @@ extern ssize_t hexport_r(struct hsearch_data *__htab,
  */
 extern int himport_r(struct hsearch_data *__htab,
 		     const char *__env, size_t __size, const char __sep,
-		     int __flag, int nvars, char * const vars[], int do_apply);
+		     int __flag, int nvars, char * const vars[]);
 
-/* Flags for himport_r() */
-#define	H_NOCLEAR	(1 << 0) /* do not clear hash table before importing */
-#define	H_FORCE		(1 << 1) /* overwrite read-only/write-once variables */
+/* Flags for himport_r(), hdelete_r(), and hsearch_r() */
+#define H_NOCLEAR	(1 << 0) /* do not clear hash table before importing */
+#define H_FORCE		(1 << 1) /* overwrite read-only/write-once variables */
+#define H_INTERACTIVE	(1 << 2) /* indicate that an import is user directed */
 
 #endif /* search.h */
diff --git a/lib/hashtable.c b/lib/hashtable.c
index 94a7b61..f0056ac 100644
--- a/lib/hashtable.c
+++ b/lib/hashtable.c
@@ -142,7 +142,7 @@ int hcreate_r(size_t nel, struct hsearch_data *htab)
  * be freed and the local static variable can be marked as not used.
  */
 
-void hdestroy_r(struct hsearch_data *htab, int do_apply)
+void hdestroy_r(struct hsearch_data *htab)
 {
 	int i;
 
@@ -156,10 +156,7 @@ void hdestroy_r(struct hsearch_data *htab, int do_apply)
 	for (i = 1; i <= htab->size; ++i) {
 		if (htab->table[i].used > 0) {
 			ENTRY *ep = &htab->table[i].entry;
-			if (do_apply && htab->apply != NULL) {
-				/* deletion is always forced */
-				htab->apply(ep->key, ep->data, NULL, H_FORCE);
-			}
+
 			free((void *)ep->key);
 			free(ep->data);
 		}
@@ -251,7 +248,7 @@ int hmatch_r(const char *match, int last_idx, ENTRY ** retval,
 }
 
 int hsearch_r(ENTRY item, ACTION action, ENTRY ** retval,
-	      struct hsearch_data *htab)
+	      struct hsearch_data *htab, int flag)
 {
 	unsigned int hval;
 	unsigned int count;
@@ -404,7 +401,7 @@ int hsearch_r(ENTRY item, ACTION action, ENTRY ** retval,
  * do that.
  */
 
-int hdelete_r(const char *key, struct hsearch_data *htab, int do_apply)
+int hdelete_r(const char *key, struct hsearch_data *htab, int flag)
 {
 	ENTRY e, *ep;
 	int idx;
@@ -413,15 +410,21 @@ int hdelete_r(const char *key, struct hsearch_data *htab, int do_apply)
 
 	e.key = (char *)key;
 
-	if ((idx = hsearch_r(e, FIND, &ep, htab)) == 0) {
+	idx = hsearch_r(e, FIND, &ep, htab, 0);
+	if (idx == 0) {
 		__set_errno(ESRCH);
 		return 0;	/* not found */
 	}
 
+	/* Check for permission */
+	if (htab->apply != NULL &&
+	    htab->apply(ep->key, ep->data, NULL, flag)) {
+		__set_errno(EPERM);
+		return 0;
+	}
+
 	/* free used ENTRY */
 	debug("hdelete: DELETING key \"%s\"\n", key);
-	if (do_apply && htab->apply != NULL)
-		htab->apply(ep->key, ep->data, NULL, H_FORCE);
 	free((void *)ep->key);
 	free(ep->data);
 	htab->table[idx].used = -1;
@@ -674,7 +677,7 @@ static int drop_var_from_set(const char *name, int nvars, char * vars[])
 
 int himport_r(struct hsearch_data *htab,
 		const char *env, size_t size, const char sep, int flag,
-		int nvars, char * const vars[], int do_apply)
+		int nvars, char * const vars[])
 {
 	char *data, *sp, *dp, *name, *value;
 	char *localvars[nvars];
@@ -704,7 +707,7 @@ int himport_r(struct hsearch_data *htab,
 		debug("Destroy Hash Table: %p table = %p\n", htab,
 		       htab->table);
 		if (htab->table)
-			hdestroy_r(htab, do_apply);
+			hdestroy_r(htab);
 	}
 
 	/*
@@ -770,7 +773,7 @@ int himport_r(struct hsearch_data *htab,
 			if (!drop_var_from_set(name, nvars, localvars))
 				continue;
 
-			if (hdelete_r(name, htab, do_apply) == 0)
+			if (hdelete_r(name, htab, flag) == 0)
 				debug("DELETE ERROR ##############################\n");
 
 			continue;
@@ -795,14 +798,14 @@ int himport_r(struct hsearch_data *htab,
 		e.data = value;
 
 		/* if there is an apply function, check what it has to say */
-		if (do_apply && htab->apply != NULL) {
+		if (htab->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);
+			hsearch_r(e, FIND, &rv, htab, 0);
 			debug("previous value was %s\n", rv ? rv->data : "");
 			if (htab->apply(name, rv ? rv->data : NULL,
 				value, flag)) {
@@ -812,7 +815,7 @@ int himport_r(struct hsearch_data *htab,
 			}
 		}
 
-		hsearch_r(e, ENTER, &rv, htab);
+		hsearch_r(e, ENTER, &rv, htab, flag);
 		if (rv == NULL) {
 			printf("himport_r: can't insert \"%s=%s\" into hash table\n",
 				name, value);
@@ -839,7 +842,7 @@ int himport_r(struct hsearch_data *htab,
 		 * b) if the variable was not present in current env, we notify
 		 *    it might be a typo
 		 */
-		if (hdelete_r(localvars[i], htab, do_apply) == 0)
+		if (hdelete_r(localvars[i], htab, flag) == 0)
 			printf("WARNING: '%s' neither in running nor in imported env!\n", localvars[i]);
 		else
 			printf("WARNING: '%s' not in imported env, deleting it!\n", localvars[i]);
-- 
1.7.11.5

^ permalink raw reply related	[flat|nested] 124+ messages in thread

* [U-Boot] [PATCH v3 03/18] env: Consolidate common code in hsearch_r()
  2012-11-01 16:39                                       ` [U-Boot] [PATCH v3 0/18] Add environment call-back and flags capability Joe Hershberger
  2012-11-01 16:39                                         ` [U-Boot] [PATCH v3 01/18] Make linux kernel string funcs available to tools Joe Hershberger
  2012-11-01 16:39                                         ` [U-Boot] [PATCH v3 02/18] env: Refactor do_apply to a flag Joe Hershberger
@ 2012-11-01 16:39                                         ` Joe Hershberger
  2012-11-01 16:39                                         ` [U-Boot] [PATCH v3 04/18] env: Refactor apply into change_ok Joe Hershberger
                                                           ` (16 subsequent siblings)
  19 siblings, 0 replies; 124+ messages in thread
From: Joe Hershberger @ 2012-11-01 16:39 UTC (permalink / raw)
  To: u-boot

The same chunk of code was replicated in two places and the following
changes will make that chunk grow a bit, so combine into a static func.

Signed-off-by: Joe Hershberger <joe.hershberger@ni.com>
---

 lib/hashtable.c | 71 ++++++++++++++++++++++++++++++---------------------------
 1 file changed, 37 insertions(+), 34 deletions(-)

diff --git a/lib/hashtable.c b/lib/hashtable.c
index f0056ac..f4d5795 100644
--- a/lib/hashtable.c
+++ b/lib/hashtable.c
@@ -247,6 +247,34 @@ int hmatch_r(const char *match, int last_idx, ENTRY ** retval,
 	return 0;
 }
 
+/*
+ * Compare an existing entry with the desired key, and overwrite if the action
+ * is ENTER.  This is simply a helper function for hsearch_r().
+ */
+static inline int _compare_and_overwrite_entry(ENTRY item, ACTION action,
+	ENTRY **retval, struct hsearch_data *htab, int flag,
+	unsigned int hval, unsigned int idx)
+{
+	if (htab->table[idx].used == hval
+	    && strcmp(item.key, htab->table[idx].entry.key) == 0) {
+		/* Overwrite existing value? */
+		if ((action == ENTER) && (item.data != NULL)) {
+			free(htab->table[idx].entry.data);
+			htab->table[idx].entry.data = strdup(item.data);
+			if (!htab->table[idx].entry.data) {
+				__set_errno(ENOMEM);
+				*retval = NULL;
+				return 0;
+			}
+		}
+		/* return found entry */
+		*retval = &htab->table[idx].entry;
+		return idx;
+	}
+	/* keep searching */
+	return -1;
+}
+
 int hsearch_r(ENTRY item, ACTION action, ENTRY ** retval,
 	      struct hsearch_data *htab, int flag)
 {
@@ -255,6 +283,7 @@ int hsearch_r(ENTRY item, ACTION action, ENTRY ** retval,
 	unsigned int len = strlen(item.key);
 	unsigned int idx;
 	unsigned int first_deleted = 0;
+	int ret;
 
 	/* Compute an value for the given string. Perhaps use a better method. */
 	hval = len;
@@ -286,23 +315,10 @@ int hsearch_r(ENTRY item, ACTION action, ENTRY ** retval,
 		    && !first_deleted)
 			first_deleted = idx;
 
-		if (htab->table[idx].used == hval
-		    && strcmp(item.key, htab->table[idx].entry.key) == 0) {
-			/* Overwrite existing value? */
-			if ((action == ENTER) && (item.data != NULL)) {
-				free(htab->table[idx].entry.data);
-				htab->table[idx].entry.data =
-					strdup(item.data);
-				if (!htab->table[idx].entry.data) {
-					__set_errno(ENOMEM);
-					*retval = NULL;
-					return 0;
-				}
-			}
-			/* return found entry */
-			*retval = &htab->table[idx].entry;
-			return idx;
-		}
+		ret = _compare_and_overwrite_entry(item, action, retval, htab,
+			flag, hval, idx);
+		if (ret != -1)
+			return ret;
 
 		/*
 		 * Second hash function:
@@ -328,23 +344,10 @@ int hsearch_r(ENTRY item, ACTION action, ENTRY ** retval,
 				break;
 
 			/* If entry is found use it. */
-			if ((htab->table[idx].used == hval)
-			    && strcmp(item.key, htab->table[idx].entry.key) == 0) {
-				/* Overwrite existing value? */
-				if ((action == ENTER) && (item.data != NULL)) {
-					free(htab->table[idx].entry.data);
-					htab->table[idx].entry.data =
-						strdup(item.data);
-					if (!htab->table[idx].entry.data) {
-						__set_errno(ENOMEM);
-						*retval = NULL;
-						return 0;
-					}
-				}
-				/* return found entry */
-				*retval = &htab->table[idx].entry;
-				return idx;
-			}
+			ret = _compare_and_overwrite_entry(item, action, retval,
+				htab, flag, hval, idx);
+			if (ret != -1)
+				return ret;
 		}
 		while (htab->table[idx].used);
 	}
-- 
1.7.11.5

^ permalink raw reply related	[flat|nested] 124+ messages in thread

* [U-Boot] [PATCH v3 04/18] env: Refactor apply into change_ok
  2012-11-01 16:39                                       ` [U-Boot] [PATCH v3 0/18] Add environment call-back and flags capability Joe Hershberger
                                                           ` (2 preceding siblings ...)
  2012-11-01 16:39                                         ` [U-Boot] [PATCH v3 03/18] env: Consolidate common code in hsearch_r() Joe Hershberger
@ 2012-11-01 16:39                                         ` Joe Hershberger
  2012-11-01 16:39                                         ` [U-Boot] [PATCH v3 05/18] env: Use getenv_yesno() more generally Joe Hershberger
                                                           ` (15 subsequent siblings)
  19 siblings, 0 replies; 124+ messages in thread
From: Joe Hershberger @ 2012-11-01 16:39 UTC (permalink / raw)
  To: u-boot

Move the read of the old value to inside the check function.  In some
cases it can be avoided all together and at the least the code is only
called from one place.

Also name the function and the callback to more clearly describe what
it does.

Pass the ENTRY instead of just the name for direct access to the whole
data structure.

Pass an enum to the callback that specifies the operation being approved.

Signed-off-by: Joe Hershberger <joe.hershberger@ni.com>
---
Changes in v3:
- Split hdelete_r() into the core delete and the validation before
delete
- Delete vars on failed insertion

 common/cmd_nvedit.c   | 34 +++++++++++--------------
 common/env_common.c   |  2 +-
 include/environment.h |  7 +++---
 include/search.h      | 13 +++++++---
 lib/hashtable.c       | 70 +++++++++++++++++++++++++++++++--------------------
 5 files changed, 71 insertions(+), 55 deletions(-)

diff --git a/common/cmd_nvedit.c b/common/cmd_nvedit.c
index 4820008..119796b 100644
--- a/common/cmd_nvedit.c
+++ b/common/cmd_nvedit.c
@@ -207,10 +207,20 @@ static int do_env_grep(cmd_tbl_t *cmdtp, int flag,
  * overwriting of write-once variables.
  */
 
-int env_check_apply(const char *name, const char *oldval,
-			const char *newval, int flag)
+int env_change_ok(const ENTRY *item, const char *newval, enum env_op op,
+	int flag)
 {
 	int   console = -1;
+	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 ? : "";
@@ -241,12 +251,12 @@ int env_check_apply(const char *name, const char *oldval,
 #endif /* CONFIG_CONSOLE_MUX */
 	}
 
+#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.
 	 */
-#ifndef CONFIG_ENV_OVERWRITE
-	if (oldval != NULL &&			/* variable exists */
+	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
@@ -264,7 +274,7 @@ int env_check_apply(const char *name, const char *oldval,
 	 * (which will erase all variables prior to calling this),
 	 * we want the baudrate to actually change - for real.
 	 */
-	if (oldval != NULL ||			/* variable exists */
+	if (op != env_op_create ||		/* variable exists */
 		(flag & H_NOCLEAR) == 0) {	/* or env is clear */
 		/*
 		 * Switch to new baudrate if new baudrate is supported
@@ -338,20 +348,6 @@ int _do_env_set(int flag, int argc, char * const argv[])
 	}
 
 	env_id++;
-	/*
-	 * search if variable with this name already exists
-	 */
-	e.key = name;
-	e.data = NULL;
-	hsearch_r(e, FIND, &ep, &env_htab, 0);
-
-	/*
-	 * Perform requested checks.
-	 */
-	if (env_check_apply(name, ep ? ep->data : NULL, value, 0)) {
-		debug("check function did not approve, refusing\n");
-		return 1;
-	}
 
 	/* Delete only ? */
 	if (argc < 3 || argv[2] == NULL) {
diff --git a/common/env_common.c b/common/env_common.c
index f22f5b9..919f535 100644
--- a/common/env_common.c
+++ b/common/env_common.c
@@ -40,7 +40,7 @@ DECLARE_GLOBAL_DATA_PTR;
 #include <env_default.h>
 
 struct hsearch_data env_htab = {
-	.apply = env_check_apply,
+	.change_ok = env_change_ok,
 };
 
 static uchar __env_get_char_spec(int index)
diff --git a/include/environment.h b/include/environment.h
index e8ab703..4b19f32 100644
--- a/include/environment.h
+++ b/include/environment.h
@@ -188,13 +188,12 @@ int set_default_vars(int nvars, char * const vars[]);
 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).
+ * Check if variable "item" can be changed to newval
  * When (flag & H_FORCE) is set, it does not print out any error
  * message and forces overwriting of write-once variables.
  */
-int env_check_apply(const char *name, const char *oldval,
-			const char *newval, int flag);
+int env_change_ok(const ENTRY *item, const char *newval, enum env_op op,
+	int flag);
 
 #endif /* DO_DEPS_ONLY */
 
diff --git a/include/search.h b/include/search.h
index f5165b0..fa00ea1 100644
--- a/include/search.h
+++ b/include/search.h
@@ -32,6 +32,12 @@
 
 #define __set_errno(val) do { errno = val; } while (0)
 
+enum env_op {
+	env_op_create,
+	env_op_delete,
+	env_op_overwrite,
+};
+
 /* Action which shall be performed in the call the hsearch.  */
 typedef enum {
 	FIND,
@@ -59,14 +65,13 @@ struct hsearch_data {
 	unsigned int filled;
 /*
  * Callback function which will check whether the given change for variable
- * "name" from "oldval" to "newval" may be applied or not, and possibly apply
- * such change.
+ * "item" to "newval" may be applied or not, and possibly apply such change.
  * When (flag & H_FORCE) is set, it shall not print out any error message and
  * shall force overwriting of write-once variables.
 .* Must return 0 for approval, 1 for denial.
  */
-	int (*apply)(const char *name, const char *oldval,
-			const char *newval, int flag);
+	int (*change_ok)(const ENTRY *__item, const char *newval, enum env_op,
+		int flag);
 };
 
 /* Create a new hashing table which will at most contain NEL elements.  */
diff --git a/lib/hashtable.c b/lib/hashtable.c
index f4d5795..6861a42 100644
--- a/lib/hashtable.c
+++ b/lib/hashtable.c
@@ -66,12 +66,16 @@
  * Instead the interface of all functions is extended to take an argument
  * which describes the current status.
  */
+
 typedef struct _ENTRY {
 	int used;
 	ENTRY entry;
 } _ENTRY;
 
 
+static void _hdelete(const char *key, struct hsearch_data *htab, ENTRY *ep,
+	int idx);
+
 /*
  * hcreate()
  */
@@ -259,6 +263,17 @@ static inline int _compare_and_overwrite_entry(ENTRY item, ACTION action,
 	    && strcmp(item.key, htab->table[idx].entry.key) == 0) {
 		/* Overwrite existing value? */
 		if ((action == ENTER) && (item.data != NULL)) {
+			/* check for permission */
+			if (htab->change_ok != NULL && htab->change_ok(
+			    &htab->table[idx].entry, item.data,
+			    env_op_overwrite, flag)) {
+				debug("change_ok() rejected setting variable "
+					"%s, skipping it!\n", item.key);
+				__set_errno(EPERM);
+				*retval = NULL;
+				return 0;
+			}
+
 			free(htab->table[idx].entry.data);
 			htab->table[idx].entry.data = strdup(item.data);
 			if (!htab->table[idx].entry.data) {
@@ -383,6 +398,17 @@ int hsearch_r(ENTRY item, ACTION action, ENTRY ** retval,
 
 		++htab->filled;
 
+		/* check for permission */
+		if (htab->change_ok != NULL && htab->change_ok(
+		    &htab->table[idx].entry, item.data, env_op_create, flag)) {
+			debug("change_ok() rejected setting variable "
+				"%s, skipping it!\n", item.key);
+			_hdelete(item.key, htab, &htab->table[idx].entry, idx);
+			__set_errno(EPERM);
+			*retval = NULL;
+			return 0;
+		}
+
 		/* return new entry */
 		*retval = &htab->table[idx].entry;
 		return 1;
@@ -404,6 +430,18 @@ int hsearch_r(ENTRY item, ACTION action, ENTRY ** retval,
  * do that.
  */
 
+static void _hdelete(const char *key, struct hsearch_data *htab, ENTRY *ep,
+	int idx)
+{
+	/* free used ENTRY */
+	debug("hdelete: DELETING key \"%s\"\n", key);
+	free((void *)ep->key);
+	free(ep->data);
+	htab->table[idx].used = -1;
+
+	--htab->filled;
+}
+
 int hdelete_r(const char *key, struct hsearch_data *htab, int flag)
 {
 	ENTRY e, *ep;
@@ -420,19 +458,15 @@ int hdelete_r(const char *key, struct hsearch_data *htab, int flag)
 	}
 
 	/* Check for permission */
-	if (htab->apply != NULL &&
-	    htab->apply(ep->key, ep->data, NULL, flag)) {
+	if (htab->change_ok != NULL &&
+	    htab->change_ok(ep, NULL, env_op_delete, flag)) {
+		debug("change_ok() rejected deleting variable "
+			"%s, skipping it!\n", key);
 		__set_errno(EPERM);
 		return 0;
 	}
 
-	/* free used ENTRY */
-	debug("hdelete: DELETING key \"%s\"\n", key);
-	free((void *)ep->key);
-	free(ep->data);
-	htab->table[idx].used = -1;
-
-	--htab->filled;
+	_hdelete(key, htab, ep, idx);
 
 	return 1;
 }
@@ -800,24 +834,6 @@ int himport_r(struct hsearch_data *htab,
 		e.key = name;
 		e.data = value;
 
-		/* if there is an apply function, check what it has to say */
-		if (htab->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, 0);
-			debug("previous value was %s\n", rv ? rv->data : "");
-			if (htab->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, flag);
 		if (rv == NULL) {
 			printf("himport_r: can't insert \"%s=%s\" into hash table\n",
-- 
1.7.11.5

^ permalink raw reply related	[flat|nested] 124+ messages in thread

* [U-Boot] [PATCH v3 05/18] env: Use getenv_yesno() more generally
  2012-11-01 16:39                                       ` [U-Boot] [PATCH v3 0/18] Add environment call-back and flags capability Joe Hershberger
                                                           ` (3 preceding siblings ...)
  2012-11-01 16:39                                         ` [U-Boot] [PATCH v3 04/18] env: Refactor apply into change_ok Joe Hershberger
@ 2012-11-01 16:39                                         ` Joe Hershberger
  2012-11-01 16:39                                         ` [U-Boot] [PATCH v3 06/18] env: Hide '.' variables in env print by default Joe Hershberger
                                                           ` (14 subsequent siblings)
  19 siblings, 0 replies; 124+ messages in thread
From: Joe Hershberger @ 2012-11-01 16:39 UTC (permalink / raw)
  To: u-boot

Move the getenv_yesno() to env_common.c and change most checks for
'y' or 'n' to use this helper.

Signed-off-by: Joe Hershberger <joe.hershberger@ni.com>
---

 arch/arm/lib/board.c            |  4 +---
 arch/m68k/lib/board.c           |  3 +--
 arch/microblaze/lib/board.c     |  4 +---
 arch/powerpc/cpu/mpc85xx/mp.c   |  4 +---
 arch/powerpc/lib/board.c        |  9 ++-------
 arch/sparc/lib/board.c          |  3 +--
 board/Marvell/db64360/db64360.c | 10 +++-------
 board/Marvell/db64460/db64460.c | 10 +++-------
 board/esd/cpci750/cpci750.c     | 10 +++-------
 board/gw8260/gw8260.c           | 10 +++-------
 board/prodrive/p3mx/p3mx.c      | 10 +++-------
 common/env_common.c             | 14 ++++++++++++++
 common/image.c                  |  6 ------
 include/common.h                |  5 +++++
 include/image.h                 |  1 -
 net/net.c                       | 32 +++++++++++++++-----------------
 16 files changed, 56 insertions(+), 79 deletions(-)

diff --git a/arch/arm/lib/board.c b/arch/arm/lib/board.c
index 92cad9a..2e7a9b5 100644
--- a/arch/arm/lib/board.c
+++ b/arch/arm/lib/board.c
@@ -532,15 +532,13 @@ void board_init_r(gd_t *id, ulong dest_addr)
 	flash_size = flash_init();
 	if (flash_size > 0) {
 # ifdef CONFIG_SYS_FLASH_CHECKSUM
-		char *s = getenv("flashchecksum");
-
 		print_size(flash_size, "");
 		/*
 		 * Compute and print flash CRC if flashchecksum is set to 'y'
 		 *
 		 * NOTE: Maybe we should add some WATCHDOG_RESET()? XXX
 		 */
-		if (s && (*s == 'y')) {
+		if (getenv_yesno("flashchecksum") == 1) {
 			printf("  CRC: %08X", crc32(0,
 				(const unsigned char *) CONFIG_SYS_FLASH_BASE,
 				flash_size));
diff --git a/arch/m68k/lib/board.c b/arch/m68k/lib/board.c
index 02d73fd..794b867 100644
--- a/arch/m68k/lib/board.c
+++ b/arch/m68k/lib/board.c
@@ -462,8 +462,7 @@ void board_init_r (gd_t *id, ulong dest_addr)
 		 *
 		 * NOTE: Maybe we should add some WATCHDOG_RESET()? XXX
 		 */
-		s = getenv ("flashchecksum");
-		if (s && (*s == 'y')) {
+		if (getenv_yesno("flashchecksum") == 1) {
 			printf ("  CRC: %08X",
 					crc32 (0,
 						   (const unsigned char *) CONFIG_SYS_FLASH_BASE,
diff --git a/arch/microblaze/lib/board.c b/arch/microblaze/lib/board.c
index efd63cd..a7c2f76 100644
--- a/arch/microblaze/lib/board.c
+++ b/arch/microblaze/lib/board.c
@@ -74,7 +74,6 @@ void board_init_f(ulong not_used)
 	gd = (gd_t *) (CONFIG_SYS_SDRAM_BASE + CONFIG_SYS_GBL_DATA_OFFSET);
 	bd = (bd_t *) (CONFIG_SYS_SDRAM_BASE + CONFIG_SYS_GBL_DATA_OFFSET \
 						- GENERATED_BD_INFO_SIZE);
-	__maybe_unused char *s;
 #if defined(CONFIG_CMD_FLASH)
 	ulong flash_size = 0;
 #endif
@@ -143,8 +142,7 @@ void board_init_f(ulong not_used)
 		 *
 		 * NOTE: Maybe we should add some WATCHDOG_RESET()? XXX
 		 */
-		s = getenv ("flashchecksum");
-		if (s && (*s == 'y')) {
+		if (getenv_yesno("flashchecksum") == 1) {
 			printf ("  CRC: %08X",
 				crc32(0, (const u8 *)bd->bi_flashstart,
 							flash_size)
diff --git a/arch/powerpc/cpu/mpc85xx/mp.c b/arch/powerpc/cpu/mpc85xx/mp.c
index e1197ac..43d4836 100644
--- a/arch/powerpc/cpu/mpc85xx/mp.c
+++ b/arch/powerpc/cpu/mpc85xx/mp.c
@@ -46,10 +46,8 @@ u32 get_my_id()
  */
 int hold_cores_in_reset(int verbose)
 {
-	const char *s = getenv("mp_holdoff");
-
 	/* Default to no, overriden by 'y', 'yes', 'Y', 'Yes', or '1' */
-	if (s && (*s == 'y' || *s == 'Y' || *s == '1')) {
+	if (getenv_yesno("mp_holdoff") == 1) {
 		if (verbose) {
 			puts("Secondary cores are being held in reset.\n");
 			puts("See 'mp_holdoff' environment variable\n");
diff --git a/arch/powerpc/lib/board.c b/arch/powerpc/lib/board.c
index ebf4008..b918c01 100644
--- a/arch/powerpc/lib/board.c
+++ b/arch/powerpc/lib/board.c
@@ -739,16 +739,13 @@ void board_init_r(gd_t *id, ulong dest_addr)
 		flash_size = 0;
 	} else if ((flash_size = flash_init()) > 0) {
 #ifdef CONFIG_SYS_FLASH_CHECKSUM
-		char *s;
-
 		print_size(flash_size, "");
 		/*
 		 * Compute and print flash CRC if flashchecksum is set to 'y'
 		 *
 		 * NOTE: Maybe we should add some WATCHDOG_RESET()? XXX
 		 */
-		s = getenv("flashchecksum");
-		if (s && (*s == 'y')) {
+		if (getenv_yesno("flashchecksum") == 1) {
 			printf("  CRC: %08X",
 			       crc32(0,
 				     (const unsigned char *)
@@ -841,9 +838,7 @@ void board_init_r(gd_t *id, ulong dest_addr)
 	 * "i2cfast" into account
 	 */
 	{
-		char *s = getenv("i2cfast");
-
-		if (s && ((*s == 'y') || (*s == 'Y'))) {
+		if (getenv_yesno("i2cfast") == 1) {
 			bd->bi_iic_fast[0] = 1;
 			bd->bi_iic_fast[1] = 1;
 		}
diff --git a/arch/sparc/lib/board.c b/arch/sparc/lib/board.c
index 32d025a..1b5e995 100644
--- a/arch/sparc/lib/board.c
+++ b/arch/sparc/lib/board.c
@@ -284,8 +284,7 @@ void board_init_f(ulong bootflag)
 		 *
 		 * NOTE: Maybe we should add some WATCHDOG_RESET()? XXX
 		 */
-		s = getenv("flashchecksum");
-		if (s && (*s == 'y')) {
+		if (getenv_yesno("flashchecksum") == 1) {
 			printf("  CRC: %08lX",
 			       crc32(0, (const unsigned char *)CONFIG_SYS_FLASH_BASE,
 				     flash_size)
diff --git a/board/Marvell/db64360/db64360.c b/board/Marvell/db64360/db64360.c
index 6cae686..38769e0 100644
--- a/board/Marvell/db64360/db64360.c
+++ b/board/Marvell/db64360/db64360.c
@@ -834,15 +834,11 @@ int mem_test_walk (void)
 /*********************************************************************/
 int testdram (void)
 {
-	char *s;
 	int rundata, runaddress, runwalk;
 
-	s = getenv ("testdramdata");
-	rundata = (s && (*s == 'y')) ? 1 : 0;
-	s = getenv ("testdramaddress");
-	runaddress = (s && (*s == 'y')) ? 1 : 0;
-	s = getenv ("testdramwalk");
-	runwalk = (s && (*s == 'y')) ? 1 : 0;
+	rundata = getenv_yesno("testdramdata") == 1;
+	runaddress = getenv_yesno("testdramaddress") == 1;
+	runwalk = getenv_yesno("testdramwalk") == 1;
 
 /*    rundata = 1; */
 /*    runaddress = 0; */
diff --git a/board/Marvell/db64460/db64460.c b/board/Marvell/db64460/db64460.c
index d4f58b3..ddb7ed5 100644
--- a/board/Marvell/db64460/db64460.c
+++ b/board/Marvell/db64460/db64460.c
@@ -834,15 +834,11 @@ int mem_test_walk (void)
 /*********************************************************************/
 int testdram (void)
 {
-	char *s;
 	int rundata, runaddress, runwalk;
 
-	s = getenv ("testdramdata");
-	rundata = (s && (*s == 'y')) ? 1 : 0;
-	s = getenv ("testdramaddress");
-	runaddress = (s && (*s == 'y')) ? 1 : 0;
-	s = getenv ("testdramwalk");
-	runwalk = (s && (*s == 'y')) ? 1 : 0;
+	rundata = getenv_yesno("testdramdata") == 1;
+	runaddress = getenv_yesno("testdramaddress") == 1;
+	runwalk = getenv_yesno("testdramwalk") == 1;
 
 /*    rundata = 1; */
 /*    runaddress = 0; */
diff --git a/board/esd/cpci750/cpci750.c b/board/esd/cpci750/cpci750.c
index 98051fb..d7deae4 100644
--- a/board/esd/cpci750/cpci750.c
+++ b/board/esd/cpci750/cpci750.c
@@ -953,22 +953,18 @@ int mem_test_walk (void)
 /*********************************************************************/
 int testdram (void)
 {
-	char *s;
 	int rundata    = 0;
 	int runaddress = 0;
 	int runwalk    = 0;
 
 #ifdef CONFIG_SYS_DRAM_TEST_DATA
-	s = getenv ("testdramdata");
-	rundata = (s && (*s == 'y')) ? 1 : 0;
+	rundata = getenv_yesno("testdramdata") == 1;
 #endif
 #ifdef CONFIG_SYS_DRAM_TEST_ADDRESS
-	s = getenv ("testdramaddress");
-	runaddress = (s && (*s == 'y')) ? 1 : 0;
+	runaddress = getenv_yesno("testdramaddress") == 1;
 #endif
 #ifdef CONFIG_SYS_DRAM_TEST_WALK
-	s = getenv ("testdramwalk");
-	runwalk = (s && (*s == 'y')) ? 1 : 0;
+	runwalk = getenv_yesno("testdramwalk") == 1;
 #endif
 
 	if ((rundata == 1) || (runaddress == 1) || (runwalk == 1)) {
diff --git a/board/gw8260/gw8260.c b/board/gw8260/gw8260.c
index 77a1e1d..64c54d5 100644
--- a/board/gw8260/gw8260.c
+++ b/board/gw8260/gw8260.c
@@ -544,15 +544,11 @@ int mem_test_walk (void)
 /*********************************************************************/
 int testdram (void)
 {
-	char *s;
 	int rundata, runaddress, runwalk;
 
-	s = getenv ("testdramdata");
-	rundata = (s && (*s == 'y')) ? 1 : 0;
-	s = getenv ("testdramaddress");
-	runaddress = (s && (*s == 'y')) ? 1 : 0;
-	s = getenv ("testdramwalk");
-	runwalk = (s && (*s == 'y')) ? 1 : 0;
+	rundata = getenv_yesno("testdramdata") == 1;
+	runaddress = getenv_yesno("testdramaddress") == 1;
+	runwalk = getenv_yesno("testdramwalk") == 1;
 
 	if ((rundata == 1) || (runaddress == 1) || (runwalk == 1)) {
 		printf ("Testing RAM ... ");
diff --git a/board/prodrive/p3mx/p3mx.c b/board/prodrive/p3mx/p3mx.c
index 389affc..c3fd191 100644
--- a/board/prodrive/p3mx/p3mx.c
+++ b/board/prodrive/p3mx/p3mx.c
@@ -768,22 +768,18 @@ int mem_test_walk (void)
 /*********************************************************************/
 int testdram (void)
 {
-	char *s;
 	int rundata    = 0;
 	int runaddress = 0;
 	int runwalk    = 0;
 
 #ifdef CONFIG_SYS_DRAM_TEST_DATA
-	s = getenv ("testdramdata");
-	rundata = (s && (*s == 'y')) ? 1 : 0;
+	rundata = getenv_yesno("testdramdata") == 1;
 #endif
 #ifdef CONFIG_SYS_DRAM_TEST_ADDRESS
-	s = getenv ("testdramaddress");
-	runaddress = (s && (*s == 'y')) ? 1 : 0;
+	runaddress = getenv_yesno("testdramaddress") == 1;
 #endif
 #ifdef CONFIG_SYS_DRAM_TEST_WALK
-	s = getenv ("testdramwalk");
-	runwalk = (s && (*s == 'y')) ? 1 : 0;
+	runwalk = getenv_yesno("testdramwalk") == 1;
 #endif
 
 	if ((rundata == 1) || (runaddress == 1) || (runwalk == 1))
diff --git a/common/env_common.c b/common/env_common.c
index 919f535..a86f061 100644
--- a/common/env_common.c
+++ b/common/env_common.c
@@ -81,6 +81,20 @@ const uchar *env_get_addr(int index)
 		return &default_environment[index];
 }
 
+/*
+ * Read an environment variable as a boolean
+ * Return -1 if variable does not exist (default to true)
+ */
+int getenv_yesno(const char *var)
+{
+	char *s = getenv(var);
+
+	if (s == NULL)
+		return -1;
+	return (*s == '1' || *s == 'y' || *s == 'Y' || *s == 't' || *s == 'T') ?
+		1 : 0;
+}
+
 void set_default_env(const char *s)
 {
 	int flags = 0;
diff --git a/common/image.c b/common/image.c
index 750a98b..60428c7 100644
--- a/common/image.c
+++ b/common/image.c
@@ -416,12 +416,6 @@ static const image_header_t *image_get_ramdisk(ulong rd_addr, uint8_t arch,
 /* Shared dual-format routines */
 /*****************************************************************************/
 #ifndef USE_HOSTCC
-int getenv_yesno(char *var)
-{
-	char *s = getenv(var);
-	return (s && (*s == 'n')) ? 0 : 1;
-}
-
 ulong getenv_bootm_low(void)
 {
 	char *s = getenv("bootm_low");
diff --git a/include/common.h b/include/common.h
index b23e90b..ebd4bff 100644
--- a/include/common.h
+++ b/include/common.h
@@ -340,6 +340,11 @@ int	envmatch     (uchar *, int);
 char	*getenv	     (const char *);
 int	getenv_f     (const char *name, char *buf, unsigned len);
 ulong getenv_ulong(const char *name, int base, ulong default_val);
+/*
+ * Read an environment variable as a boolean
+ * Return -1 if variable does not exist (default to true)
+ */
+int getenv_yesno(const char *var);
 int	saveenv	     (void);
 #ifdef CONFIG_PPC		/* ARM version to be fixed! */
 int inline setenv    (const char *, const char *);
diff --git a/include/image.h b/include/image.h
index 4e5863f..544334c 100644
--- a/include/image.h
+++ b/include/image.h
@@ -459,7 +459,6 @@ static inline void image_set_name(image_header_t *hdr, const char *name)
 int image_check_hcrc(const image_header_t *hdr);
 int image_check_dcrc(const image_header_t *hdr);
 #ifndef USE_HOSTCC
-int getenv_yesno(char *var);
 ulong getenv_bootm_low(void);
 phys_size_t getenv_bootm_size(void);
 phys_size_t getenv_bootm_mapsize(void);
diff --git a/net/net.c b/net/net.c
index 569fec4..c1fe00a 100644
--- a/net/net.c
+++ b/net/net.c
@@ -214,26 +214,24 @@ static int NetTryCount;
  */
 void net_auto_load(void)
 {
+#if defined(CONFIG_CMD_NFS)
 	const char *s = getenv("autoload");
 
-	if (s != NULL) {
-		if (*s == 'n') {
-			/*
-			 * Just use BOOTP/RARP to configure system;
-			 * Do not use TFTP to load the bootfile.
-			 */
-			net_set_state(NETLOOP_SUCCESS);
-			return;
-		}
-#if defined(CONFIG_CMD_NFS)
-		if (strcmp(s, "NFS") == 0) {
-			/*
-			 * Use NFS to load the bootfile.
-			 */
-			NfsStart();
-			return;
-		}
+	if (s != NULL && strcmp(s, "NFS") == 0) {
+		/*
+		 * Use NFS to load the bootfile.
+		 */
+		NfsStart();
+		return;
+	}
 #endif
+	if (getenv_yesno("autoload") == 0) {
+		/*
+		 * Just use BOOTP/RARP to configure system;
+		 * Do not use TFTP to load the bootfile.
+		 */
+		net_set_state(NETLOOP_SUCCESS);
+		return;
 	}
 	TftpStart(TFTPGET);
 }
-- 
1.7.11.5

^ permalink raw reply related	[flat|nested] 124+ messages in thread

* [U-Boot] [PATCH v3 06/18] env: Hide '.' variables in env print by default
  2012-11-01 16:39                                       ` [U-Boot] [PATCH v3 0/18] Add environment call-back and flags capability Joe Hershberger
                                                           ` (4 preceding siblings ...)
  2012-11-01 16:39                                         ` [U-Boot] [PATCH v3 05/18] env: Use getenv_yesno() more generally Joe Hershberger
@ 2012-11-01 16:39                                         ` Joe Hershberger
  2012-11-02 10:44                                           ` Luka Perkov
  2012-11-01 16:39                                         ` [U-Boot] [PATCH v3 07/18] env: Add support for callbacks to environment vars Joe Hershberger
                                                           ` (13 subsequent siblings)
  19 siblings, 1 reply; 124+ messages in thread
From: Joe Hershberger @ 2012-11-01 16:39 UTC (permalink / raw)
  To: u-boot

When printing all variables with env print, don't print variables that
begin with '.'.  If env print is called with a '-a' switch, then
include variables that begin with '.' (just like the ls command).

Variables printed explicitly will be printed even without the -a.

Signed-off-by: Joe Hershberger <joe.hershberger@ni.com>
---

 board/esd/pmc440/cmd_pmc440.c |  2 +-
 common/cmd_nvedit.c           | 24 ++++++++++++++++--------
 common/env_dataflash.c        |  2 +-
 common/env_eeprom.c           |  2 +-
 common/env_fat.c              |  2 +-
 common/env_flash.c            |  4 ++--
 common/env_mmc.c              |  2 +-
 common/env_nand.c             |  4 ++--
 common/env_nvram.c            |  2 +-
 common/env_onenand.c          |  2 +-
 common/env_sf.c               |  4 ++--
 include/search.h              |  5 +++--
 lib/hashtable.c               |  5 ++++-
 13 files changed, 36 insertions(+), 24 deletions(-)

diff --git a/board/esd/pmc440/cmd_pmc440.c b/board/esd/pmc440/cmd_pmc440.c
index f1ffb7b..e9a78a3 100644
--- a/board/esd/pmc440/cmd_pmc440.c
+++ b/board/esd/pmc440/cmd_pmc440.c
@@ -391,7 +391,7 @@ int do_painit(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
 	nextbase -= ((CONFIG_ENV_SIZE + 4096 - 1) & ~(4096 - 1));
 	envp = (env_t *)nextbase;
 	res = (char *)envp->data;
-	len = hexport_r(&env_htab, '\0', &res, ENV_SIZE, 0, NULL);
+	len = hexport_r(&env_htab, '\0', 0, &res, ENV_SIZE, 0, NULL);
 	if (len < 0) {
 		error("Cannot export environment: errno = %d\n", errno);
 		return 1;
diff --git a/common/cmd_nvedit.c b/common/cmd_nvedit.c
index 119796b..a0cdc4b 100644
--- a/common/cmd_nvedit.c
+++ b/common/cmd_nvedit.c
@@ -106,7 +106,7 @@ int get_env_id(void)
  *
  * Returns 0 in case of error, or length of printed string
  */
-static int env_print(char *name)
+static int env_print(char *name, int flag)
 {
 	char *res = NULL;
 	size_t len;
@@ -116,7 +116,7 @@ static int env_print(char *name)
 
 		e.key = name;
 		e.data = NULL;
-		hsearch_r(e, FIND, &ep, &env_htab, 0);
+		hsearch_r(e, FIND, &ep, &env_htab, flag);
 		if (ep == NULL)
 			return 0;
 		len = printf("%s=%s\n", ep->key, ep->data);
@@ -124,7 +124,7 @@ static int env_print(char *name)
 	}
 
 	/* print whole list */
-	len = hexport_r(&env_htab, '\n', &res, 0, 0, NULL);
+	len = hexport_r(&env_htab, '\n', flag, &res, 0, 0, NULL);
 
 	if (len > 0) {
 		puts(res);
@@ -140,10 +140,17 @@ int do_env_print (cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
 {
 	int i;
 	int rcode = 0;
+	int env_flag = H_HIDE_DOT;
+
+	if (argc > 1 && argv[1][0] == '-' && argv[1][1] == 'a') {
+		argc--;
+		argv++;
+		env_flag &= ~H_HIDE_DOT;
+	}
 
 	if (argc == 1) {
 		/* print all env vars */
-		rcode = env_print(NULL);
+		rcode = env_print(NULL, env_flag);
 		if (!rcode)
 			return 1;
 		printf("\nEnvironment size: %d/%ld bytes\n",
@@ -152,8 +159,9 @@ int do_env_print (cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
 	}
 
 	/* print selected env vars */
+	env_flag &= ~H_HIDE_DOT;
 	for (i = 1; i < argc; ++i) {
-		int rc = env_print(argv[i]);
+		int rc = env_print(argv[i], env_flag);
 		if (!rc) {
 			printf("## Error: \"%s\" not defined\n", argv[i]);
 			++rcode;
@@ -804,7 +812,7 @@ NXTARG:		;
 	argv++;
 
 	if (sep) {		/* export as text file */
-		len = hexport_r(&env_htab, sep, &addr, size, argc, argv);
+		len = hexport_r(&env_htab, sep, 0, &addr, size, argc, argv);
 		if (len < 0) {
 			error("Cannot export environment: errno = %d\n", errno);
 			return 1;
@@ -822,7 +830,7 @@ NXTARG:		;
 	else			/* export as raw binary data */
 		res = addr;
 
-	len = hexport_r(&env_htab, '\0', &res, ENV_SIZE, argc, argv);
+	len = hexport_r(&env_htab, '\0', 0, &res, ENV_SIZE, argc, argv);
 	if (len < 0) {
 		error("Cannot export environment: errno = %d\n", errno);
 		return 1;
@@ -1062,7 +1070,7 @@ U_BOOT_CMD_COMPLETE(
 U_BOOT_CMD_COMPLETE(
 	printenv, CONFIG_SYS_MAXARGS, 1,	do_env_print,
 	"print environment variables",
-	"\n    - print values of all environment variables\n"
+	"[-a]\n    - print [all] values of all environment variables\n"
 	"printenv name ...\n"
 	"    - print value of environment variable 'name'",
 	var_complete
diff --git a/common/env_dataflash.c b/common/env_dataflash.c
index 3c5af37..38c9615 100644
--- a/common/env_dataflash.c
+++ b/common/env_dataflash.c
@@ -60,7 +60,7 @@ int saveenv(void)
 	char	*res;
 
 	res = (char *)&env_new.data;
-	len = hexport_r(&env_htab, '\0', &res, ENV_SIZE, 0, NULL);
+	len = hexport_r(&env_htab, '\0', 0, &res, ENV_SIZE, 0, NULL);
 	if (len < 0) {
 		error("Cannot export environment: errno = %d\n", errno);
 		return 1;
diff --git a/common/env_eeprom.c b/common/env_eeprom.c
index b66bba2..45c935b 100644
--- a/common/env_eeprom.c
+++ b/common/env_eeprom.c
@@ -139,7 +139,7 @@ int saveenv(void)
 	BUG_ON(env_ptr != NULL);
 
 	res = (char *)&env_new.data;
-	len = hexport_r(&env_htab, '\0', &res, ENV_SIZE, 0, NULL);
+	len = hexport_r(&env_htab, '\0', 0, &res, ENV_SIZE, 0, NULL);
 	if (len < 0) {
 		error("Cannot export environment: errno = %d\n", errno);
 		return 1;
diff --git a/common/env_fat.c b/common/env_fat.c
index 6ef5318..c0f18ab 100644
--- a/common/env_fat.c
+++ b/common/env_fat.c
@@ -61,7 +61,7 @@ int saveenv(void)
 	int err;
 
 	res = (char *)&env_new.data;
-	len = hexport_r(&env_htab, '\0', &res, ENV_SIZE, 0, NULL);
+	len = hexport_r(&env_htab, '\0', 0, &res, ENV_SIZE, 0, NULL);
 	if (len < 0) {
 		error("Cannot export environment: errno = %d\n", errno);
 		return 1;
diff --git a/common/env_flash.c b/common/env_flash.c
index aa970d4..e07d336 100644
--- a/common/env_flash.c
+++ b/common/env_flash.c
@@ -142,7 +142,7 @@ int saveenv(void)
 		goto done;
 
 	res = (char *)&env_new.data;
-	len = hexport_r(&env_htab, '\0', &res, ENV_SIZE, 0, NULL);
+	len = hexport_r(&env_htab, '\0', 0, &res, ENV_SIZE, 0, NULL);
 	if (len < 0) {
 		error("Cannot export environment: errno = %d\n", errno);
 		goto done;
@@ -275,7 +275,7 @@ int saveenv(void)
 		goto done;
 
 	res = (char *)&env_new.data;
-	len = hexport_r(&env_htab, '\0', &res, ENV_SIZE, 0, NULL);
+	len = hexport_r(&env_htab, '\0', 0, &res, ENV_SIZE, 0, NULL);
 	if (len < 0) {
 		error("Cannot export environment: errno = %d\n", errno);
 		goto done;
diff --git a/common/env_mmc.c b/common/env_mmc.c
index a2ff90b..ce21671 100644
--- a/common/env_mmc.c
+++ b/common/env_mmc.c
@@ -130,7 +130,7 @@ int saveenv(void)
 	}
 
 	res = (char *)&env_new->data;
-	len = hexport_r(&env_htab, '\0', &res, ENV_SIZE, 0, NULL);
+	len = hexport_r(&env_htab, '\0', 0, &res, ENV_SIZE, 0, NULL);
 	if (len < 0) {
 		error("Cannot export environment: errno = %d\n", errno);
 		ret = 1;
diff --git a/common/env_nand.c b/common/env_nand.c
index 79e8033..22e72a2 100644
--- a/common/env_nand.c
+++ b/common/env_nand.c
@@ -186,7 +186,7 @@ int saveenv(void)
 		return 1;
 
 	res = (char *)&env_new.data;
-	len = hexport_r(&env_htab, '\0', &res, ENV_SIZE, 0, NULL);
+	len = hexport_r(&env_htab, '\0', 0, &res, ENV_SIZE, 0, NULL);
 	if (len < 0) {
 		error("Cannot export environment: errno = %d\n", errno);
 		return 1;
@@ -239,7 +239,7 @@ int saveenv(void)
 		return 1;
 
 	res = (char *)&env_new->data;
-	len = hexport_r(&env_htab, '\0', &res, ENV_SIZE, 0, NULL);
+	len = hexport_r(&env_htab, '\0', 0, &res, ENV_SIZE, 0, NULL);
 	if (len < 0) {
 		error("Cannot export environment: errno = %d\n", errno);
 		return 1;
diff --git a/common/env_nvram.c b/common/env_nvram.c
index 6483db3..eab0e7b 100644
--- a/common/env_nvram.c
+++ b/common/env_nvram.c
@@ -90,7 +90,7 @@ int saveenv(void)
 	int	rcode = 0;
 
 	res = (char *)&env_new.data;
-	len = hexport_r(&env_htab, '\0', &res, ENV_SIZE, 0, NULL);
+	len = hexport_r(&env_htab, '\0', 0, &res, ENV_SIZE, 0, NULL);
 	if (len < 0) {
 		error("Cannot export environment: errno = %d\n", errno);
 		return 1;
diff --git a/common/env_onenand.c b/common/env_onenand.c
index da35071..faa903d 100644
--- a/common/env_onenand.c
+++ b/common/env_onenand.c
@@ -95,7 +95,7 @@ int saveenv(void)
 	};
 
 	res = (char *)&env_new.data;
-	len = hexport_r(&env_htab, '\0', &res, ENV_SIZE, 0, NULL);
+	len = hexport_r(&env_htab, '\0', 0, &res, ENV_SIZE, 0, NULL);
 	if (len < 0) {
 		error("Cannot export environment: errno = %d\n", errno);
 		return 1;
diff --git a/common/env_sf.c b/common/env_sf.c
index bbd472f..d9e9085 100644
--- a/common/env_sf.c
+++ b/common/env_sf.c
@@ -79,7 +79,7 @@ int saveenv(void)
 	}
 
 	res = (char *)&env_new.data;
-	len = hexport_r(&env_htab, '\0', &res, ENV_SIZE, 0, NULL);
+	len = hexport_r(&env_htab, '\0', 0, &res, ENV_SIZE, 0, NULL);
 	if (len < 0) {
 		error("Cannot export environment: errno = %d\n", errno);
 		return 1;
@@ -277,7 +277,7 @@ int saveenv(void)
 	}
 
 	res = (char *)&env_new.data;
-	len = hexport_r(&env_htab, '\0', &res, ENV_SIZE, 0, NULL);
+	len = hexport_r(&env_htab, '\0', 0, &res, ENV_SIZE, 0, NULL);
 	if (len < 0) {
 		error("Cannot export environment: errno = %d\n", errno);
 		goto done;
diff --git a/include/search.h b/include/search.h
index fa00ea1..1e48deb 100644
--- a/include/search.h
+++ b/include/search.h
@@ -107,7 +107,7 @@ extern int hdelete_r(const char *__key, struct hsearch_data *__htab,
 		     int __flag);
 
 extern ssize_t hexport_r(struct hsearch_data *__htab,
-		     const char __sep, char **__resp, size_t __size,
+		     const char __sep, int __flag, char **__resp, size_t __size,
 		     int argc, char * const argv[]);
 
 /*
@@ -120,9 +120,10 @@ extern int himport_r(struct hsearch_data *__htab,
 		     const char *__env, size_t __size, const char __sep,
 		     int __flag, int nvars, char * const vars[]);
 
-/* Flags for himport_r(), hdelete_r(), and hsearch_r() */
+/* Flags for himport_r(), hexport_r(), hdelete_r(), and hsearch_r() */
 #define H_NOCLEAR	(1 << 0) /* do not clear hash table before importing */
 #define H_FORCE		(1 << 1) /* overwrite read-only/write-once variables */
 #define H_INTERACTIVE	(1 << 2) /* indicate that an import is user directed */
+#define H_HIDE_DOT	(1 << 3) /* don't print env vars that begin with '.' */
 
 #endif /* search.h */
diff --git a/lib/hashtable.c b/lib/hashtable.c
index 6861a42..7c6b96c 100644
--- a/lib/hashtable.c
+++ b/lib/hashtable.c
@@ -522,7 +522,7 @@ static int cmpkey(const void *p1, const void *p2)
 	return (strcmp(e1->key, e2->key));
 }
 
-ssize_t hexport_r(struct hsearch_data *htab, const char sep,
+ssize_t hexport_r(struct hsearch_data *htab, const char sep, int flag,
 		 char **resp, size_t size,
 		 int argc, char * const argv[])
 {
@@ -559,6 +559,9 @@ ssize_t hexport_r(struct hsearch_data *htab, const char sep,
 			if ((argc > 0) && (found == 0))
 				continue;
 
+			if ((flag & H_HIDE_DOT) && ep->key[0] == '.')
+				continue;
+
 			list[n++] = ep;
 
 			totlen += strlen(ep->key) + 2;
-- 
1.7.11.5

^ permalink raw reply related	[flat|nested] 124+ messages in thread

* [U-Boot] [PATCH v3 07/18] env: Add support for callbacks to environment vars
  2012-11-01 16:39                                       ` [U-Boot] [PATCH v3 0/18] Add environment call-back and flags capability Joe Hershberger
                                                           ` (5 preceding siblings ...)
  2012-11-01 16:39                                         ` [U-Boot] [PATCH v3 06/18] env: Hide '.' variables in env print by default Joe Hershberger
@ 2012-11-01 16:39                                         ` Joe Hershberger
  2012-11-01 16:39                                         ` [U-Boot] [PATCH v3 08/18] env: Add a command to view callbacks Joe Hershberger
                                                           ` (12 subsequent siblings)
  19 siblings, 0 replies; 124+ messages in thread
From: Joe Hershberger @ 2012-11-01 16:39 UTC (permalink / raw)
  To: u-boot

Add support for per-variable callbacks to the "hashtable" functions.

Signed-off-by: Joe Hershberger <joe.hershberger@ni.com>
---
Changes in v3:
- Use Marek's linker lists instead of implementing it directly
- Rebase onto latest master
- Add flags parameter to callbacks
- Implement reverse search in env_attr_lookup()
- Fix space skipping in env_attr_lookup()
- All errors coming back from hsearch_r() are no longer fatal.  Don't
abort import on failed ENTER action.
- Removed checkpatch.pl warning

Changes in v2:
- Added much-needed documentation
- Factored out prevch and nextch in env_attr_lookup()

 README                 |  30 +++++++
 common/Makefile        |   4 +
 common/env_attr.c      | 222 +++++++++++++++++++++++++++++++++++++++++++++++++
 common/env_callback.c  | 132 +++++++++++++++++++++++++++++
 include/env_attr.h     |  55 ++++++++++++
 include/env_callback.h |  62 ++++++++++++++
 include/env_default.h  |   5 ++
 include/environment.h  |   2 +
 include/search.h       |   5 ++
 lib/hashtable.c        |  67 ++++++++++++++-
 10 files changed, 580 insertions(+), 4 deletions(-)
 create mode 100644 common/env_attr.c
 create mode 100644 common/env_callback.c
 create mode 100644 include/env_attr.h
 create mode 100644 include/env_callback.h

diff --git a/README b/README
index 22fd6b7..2834b52 100644
--- a/README
+++ b/README
@@ -4096,6 +4096,36 @@ Please note that changes to some configuration parameters may take
 only effect after the next boot (yes, that's just like Windoze :-).
 
 
+Callback functions for environment variables:
+---------------------------------------------
+
+For some environment variables, the behavior of u-boot needs to change
+when their values are changed.  This functionailty allows functions to
+be associated with arbitrary variables.  On creation, overwrite, or
+deletion, the callback will provide the opportunity for some side
+effect to happen or for the change to be rejected.
+
+The callbacks are named and associated with a function using the
+U_BOOT_ENV_CALLBACK macro in your board or driver code.
+
+These callbacks are associated with variables in one of two ways.  The
+static list can be added to by defining CONFIG_ENV_CALLBACK_LIST_STATIC
+in the board configuration to a string that defines a list of
+associations.  The list must be in the following format:
+
+	entry = variable_name[:callback_name]
+	list = entry[,list]
+
+If the callback name is not specified, then the callback is deleted.
+Spaces are also allowed anywhere in the list.
+
+Callbacks can also be associated by defining the ".callbacks" variable
+with the same list format above.  Any association in ".callbacks" will
+override any association in the static list. You can define
+CONFIG_ENV_CALLBACK_LIST_DEFAULT to a list (string) to define the
+".callbacks" envirnoment variable in the default or embedded environment.
+
+
 Command Line Parsing:
 =====================
 
diff --git a/common/Makefile b/common/Makefile
index 9e43322..af6e8f9 100644
--- a/common/Makefile
+++ b/common/Makefile
@@ -43,6 +43,8 @@ COBJS-y += cmd_nvedit.o
 COBJS-y += cmd_version.o
 
 # environment
+COBJS-y += env_attr.o
+COBJS-y += env_callback.o
 COBJS-y += env_common.o
 COBJS-$(CONFIG_ENV_IS_IN_DATAFLASH) += env_dataflash.o
 COBJS-$(CONFIG_ENV_IS_IN_EEPROM) += env_eeprom.o
@@ -197,6 +199,8 @@ endif
 ifdef CONFIG_SPL_BUILD
 COBJS-$(CONFIG_SPL_YMODEM_SUPPORT) += xyzModem.o
 COBJS-$(CONFIG_SPL_NET_SUPPORT) += cmd_nvedit.o
+COBJS-$(CONFIG_SPL_NET_SUPPORT) += env_attr.o
+COBJS-$(CONFIG_SPL_NET_SUPPORT) += env_callback.o
 COBJS-$(CONFIG_SPL_NET_SUPPORT) += env_common.o
 COBJS-$(CONFIG_SPL_NET_SUPPORT) += env_nowhere.o
 COBJS-$(CONFIG_SPL_NET_SUPPORT) += miiphyutil.o
diff --git a/common/env_attr.c b/common/env_attr.c
new file mode 100644
index 0000000..7d330a5
--- /dev/null
+++ b/common/env_attr.c
@@ -0,0 +1,222 @@
+/*
+ * (C) Copyright 2012
+ * Joe Hershberger, National Instruments, joe.hershberger at 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
+ */
+
+#include <common.h>
+#include <env_attr.h>
+#include <errno.h>
+#include <linux/string.h>
+#include <malloc.h>
+
+/*
+ * Iterate through the whole list calling the callback for each found element.
+ * "attr_list" takes the form:
+ *	attributes = [^,:\s]*
+ *	entry = name[:attributes]
+ *	list = entry[,list]
+ */
+int env_attr_walk(const char *attr_list,
+	int (*callback)(const char *name, const char *attributes))
+{
+	const char *entry, *entry_end;
+	char *name, *attributes;
+
+	if (!attr_list)
+		/* list not found */
+		return 1;
+
+	entry = attr_list;
+	do {
+		char *entry_cpy = NULL;
+
+		entry_end = strchr(entry, ENV_ATTR_LIST_DELIM);
+		/* check if this is the last entry in the list */
+		if (entry_end == NULL) {
+			int entry_len = strlen(entry);
+
+			if (entry_len) {
+				/*
+				 * allocate memory to copy the entry into since
+				 * we will need to inject '\0' chars and squash
+				 * white-space before calling the callback
+				 */
+				entry_cpy = malloc(entry_len + 1);
+				if (entry_cpy)
+					/* copy the rest of the list */
+					strcpy(entry_cpy, entry);
+				else
+					return -ENOMEM;
+			}
+		} else {
+			int entry_len = entry_end - entry;
+
+			if (entry_len) {
+				/*
+				 * allocate memory to copy the entry into since
+				 * we will need to inject '\0' chars and squash
+				 * white-space before calling the callback
+				 */
+				entry_cpy = malloc(entry_len + 1);
+				if (entry_cpy) {
+					/* copy just this entry and null term */
+					strncpy(entry_cpy, entry, entry_len);
+					entry_cpy[entry_len] = '\0';
+				} else
+					return -ENOMEM;
+			}
+		}
+
+		/* check if there is anything to process (e.g. not ",,,") */
+		if (entry_cpy != NULL) {
+			attributes = strchr(entry_cpy, ENV_ATTR_SEP);
+			/* check if there is a ':' */
+			if (attributes != NULL) {
+				/* replace the ':' with '\0' to term name */
+				*attributes++ = '\0';
+				/* remove white-space from attributes */
+				attributes = strim(attributes);
+			}
+			/* remove white-space from name */
+			name = strim(entry_cpy);
+
+			/* only call the callback if there is a name */
+			if (strlen(name) != 0) {
+				int retval = 0;
+
+				retval = callback(name, attributes);
+				if (retval) {
+					free(entry_cpy);
+					return retval;
+				}
+			}
+		}
+
+		free(entry_cpy);
+		entry = entry_end + 1;
+	} while (entry_end != NULL);
+
+	return 0;
+}
+
+/*
+ * Search for the last matching string in another string with the option to
+ * start looking at a certain point (i.e. ignore anything beyond that point).
+ */
+static char *reverse_strstr(const char *searched, const char *search_for,
+	const char *searched_start)
+{
+	char *result = NULL;
+
+	if (*search_for == '\0')
+		return (char *)searched;
+
+	for (;;) {
+		char *match = strstr(searched, search_for);
+
+		/*
+		 * Stop looking if no new match is found or looking past the
+		 * searched_start pointer
+		 */
+		if (match == NULL || (searched_start != NULL &&
+		    match + strlen(search_for) > searched_start))
+			break;
+
+		result = match;
+		searched = match + 1;
+	}
+
+	return result;
+}
+
+/*
+ * Retrieve the attributes string associated with a single name in the list
+ * There is no protection on attributes being too small for the value
+ */
+int env_attr_lookup(const char *attr_list, const char *name, char *attributes)
+{
+	const char *entry = NULL;
+
+	if (!attributes)
+		/* bad parameter */
+		return -1;
+	if (!attr_list)
+		/* list not found */
+		return 1;
+
+	entry = reverse_strstr(attr_list, name, NULL);
+	while (entry != NULL) {
+		const char *prevch = entry - 1;
+		const char *nextch = entry + strlen(name);
+
+		/* Skip spaces */
+		while (*prevch == ' ')
+			prevch--;
+		while (*nextch == ' ')
+			nextch++;
+
+		/* check for an exact match */
+		if ((entry == attr_list ||
+		     *prevch == ENV_ATTR_LIST_DELIM) &&
+		    (*nextch == ENV_ATTR_SEP ||
+		     *nextch == ENV_ATTR_LIST_DELIM ||
+		     *nextch == '\0'))
+			break;
+
+		entry = reverse_strstr(attr_list, name, entry);
+	}
+	if (entry != NULL) {
+		int len;
+
+		/* skip the name */
+		entry += strlen(name);
+		/* skip spaces */
+		while (*entry == ' ')
+			entry++;
+		if (*entry != ENV_ATTR_SEP)
+			len = 0;
+		else {
+			const char *delim;
+			static const char delims[] = {
+				ENV_ATTR_LIST_DELIM, ' ', '\0'};
+
+			/* skip the attr sep */
+			entry += 1;
+			/* skip spaces */
+			while (*entry == ' ')
+				entry++;
+
+			delim = strpbrk(entry, delims);
+			if (delim == NULL)
+				len = strlen(entry);
+			else
+				len = delim - entry;
+			memcpy(attributes, entry, len);
+		}
+		attributes[len] = '\0';
+
+		/* success */
+		return 0;
+	}
+
+	/* not found in list */
+	return 2;
+}
diff --git a/common/env_callback.c b/common/env_callback.c
new file mode 100644
index 0000000..b3989c6
--- /dev/null
+++ b/common/env_callback.c
@@ -0,0 +1,132 @@
+/*
+ * (C) Copyright 2012
+ * Joe Hershberger, National Instruments, joe.hershberger at 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
+ */
+
+#include <common.h>
+#include <environment.h>
+
+/*
+ * Look up a callback function pointer by name
+ */
+struct env_clbk_tbl *find_env_callback(const char *name)
+{
+	struct env_clbk_tbl *clbkp;
+	int i;
+	int num_callbacks = ll_entry_count(struct env_clbk_tbl, env_clbk);
+
+	if (name == NULL)
+		return NULL;
+
+	/* look up the callback in the linker-list */
+	for (i = 0, clbkp = ll_entry_start(struct env_clbk_tbl, env_clbk);
+	     i < num_callbacks;
+	     i++, clbkp++) {
+		if (strcmp(name, clbkp->name) == 0)
+			return clbkp;
+	}
+
+	return NULL;
+}
+
+/*
+ * Look for a possible callback for a newly added variable
+ * This is called specifically when the variable did not exist in the hash
+ * previously, so the blanket update did not find this variable.
+ */
+void env_callback_init(ENTRY *var_entry)
+{
+	const char *var_name = var_entry->key;
+	const char *callback_list = getenv(ENV_CALLBACK_VAR);
+	char callback_name[256] = "";
+	struct env_clbk_tbl *clbkp;
+	int ret = 1;
+
+	/* look in the ".callbacks" var for a reference to this variable */
+	if (callback_list != NULL)
+		ret = env_attr_lookup(callback_list, var_name, callback_name);
+
+	/* only if not found there, look in the static list */
+	if (ret)
+		ret = env_attr_lookup(ENV_CALLBACK_LIST_STATIC, var_name,
+			callback_name);
+
+	/* if an association was found, set the callback pointer */
+	if (!ret && strlen(callback_name)) {
+		clbkp = find_env_callback(callback_name);
+		if (clbkp != NULL)
+			var_entry->callback = clbkp->callback;
+	}
+}
+
+/*
+ * Called on each existing env var prior to the blanket update since removing
+ * a callback association should remove its callback.
+ */
+static int clear_callback(ENTRY *entry)
+{
+	entry->callback = NULL;
+
+	return 0;
+}
+
+/*
+ * Call for each element in the list that associates variables to callbacks
+ */
+static int set_callback(const char *name, const char *value)
+{
+	ENTRY e, *ep;
+	struct env_clbk_tbl *clbkp;
+
+	e.key	= name;
+	e.data	= NULL;
+	hsearch_r(e, FIND, &ep, &env_htab, 0);
+
+	/* does the env variable actually exist? */
+	if (ep != NULL) {
+		/* the assocaition delares no callback, so remove the pointer */
+		if (value == NULL || strlen(value) == 0)
+			ep->callback = NULL;
+		else {
+			/* assign the requested callback */
+			clbkp = find_env_callback(value);
+			if (clbkp != NULL)
+				ep->callback = clbkp->callback;
+		}
+	}
+
+	return 0;
+}
+
+static int on_callbacks(const char *name, const char *value, enum env_op op,
+	int flags)
+{
+	/* remove all callbacks */
+	hwalk_r(&env_htab, clear_callback);
+
+	/* configure any static callback bindings */
+	env_attr_walk(ENV_CALLBACK_LIST_STATIC, set_callback);
+	/* configure any dynamic callback bindings */
+	env_attr_walk(value, set_callback);
+
+	return 0;
+}
+U_BOOT_ENV_CALLBACK(callbacks, on_callbacks);
diff --git a/include/env_attr.h b/include/env_attr.h
new file mode 100644
index 0000000..6ef114f
--- /dev/null
+++ b/include/env_attr.h
@@ -0,0 +1,55 @@
+/*
+ * (C) Copyright 2012
+ * Joe Hershberger, National Instruments, joe.hershberger at 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
+ */
+
+#ifndef __ENV_ATTR_H__
+#define __ENV_ATTR_H__
+
+#define ENV_ATTR_LIST_DELIM	','
+#define ENV_ATTR_SEP		':'
+
+/*
+ * env_attr_walk takes as input an "attr_list" that takes the form:
+ *	attributes = [^,:\s]*
+ *	entry = name[:attributes]
+ *	list = entry[,list]
+ * It will call the "callback" function with the "name" and attribute as "value"
+ * The callback may return a non-0 to abort the list walk.
+ * This return value will be passed through to the caller.
+ * 0 is returned on success.
+ */
+extern int env_attr_walk(const char *attr_list,
+	int (*callback)(const char *name, const char *value));
+
+/*
+ * env_attr_lookup takes as input an "attr_list" with the same form as above.
+ * It also takes as input a "name" to look for.
+ * If the name is found in the list, it's value is copied into "attributes".
+ * There is no protection on attributes being too small for the value.
+ * It returns -1 if attributes is NULL, 1 if "name" is not found, 2 if
+ * "attr_list" is NULL.
+ * Returns 0 on success.
+ */
+extern int env_attr_lookup(const char *attr_list, const char *name,
+	char *attributes);
+
+#endif /* __ENV_ATTR_H__ */
diff --git a/include/env_callback.h b/include/env_callback.h
new file mode 100644
index 0000000..1a25e3f
--- /dev/null
+++ b/include/env_callback.h
@@ -0,0 +1,62 @@
+/*
+ * (C) Copyright 2012
+ * Joe Hershberger, National Instruments, joe.hershberger at 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
+ */
+
+#ifndef __ENV_CALLBACK_H__
+#define __ENV_CALLBACK_H__
+
+#include <linker_lists.h>
+#include <search.h>
+
+#define ENV_CALLBACK_VAR ".callbacks"
+
+/* Board configs can define additional static callback bindings */
+#ifndef CONFIG_ENV_CALLBACK_LIST_STATIC
+#define CONFIG_ENV_CALLBACK_LIST_STATIC
+#endif
+
+/*
+ * This list of callback bindings is static, but may be overridden by defining
+ * a new assogiation in the ".callbacks" environment variable.
+ */
+#define ENV_CALLBACK_LIST_STATIC ENV_CALLBACK_VAR ":callbacks," \
+	CONFIG_ENV_CALLBACK_LIST_STATIC
+
+struct env_clbk_tbl {
+	const char *name;		/* Callback name */
+	int (*callback)(const char *name, const char *value, enum env_op op,
+		int flags);
+};
+
+struct env_clbk_tbl *find_env_callback(const char *);
+void env_callback_init(ENTRY *var_entry);
+
+/*
+ * Define a callback that can be associated with variables.
+ * when associated through the ".callbacks" environment variable, the callback
+ * will be executed any time the variable is inserted, overwritten, or deleted.
+ */
+#define U_BOOT_ENV_CALLBACK(name, callback) \
+	ll_entry_declare(struct env_clbk_tbl, name, env_clbk, env_clbk) = \
+	{#name, callback}
+
+#endif /* __ENV_CALLBACK_H__ */
diff --git a/include/env_default.h b/include/env_default.h
index 375e5ca..cff378d 100644
--- a/include/env_default.h
+++ b/include/env_default.h
@@ -24,6 +24,8 @@
  * MA 02111-1307 USA
  */
 
+#include <env_callback.h>
+
 #ifdef DEFAULT_ENV_INSTANCE_EMBEDDED
 env_t environment __PPCENV__ = {
 	ENV_CRC,	/* CRC Sum */
@@ -36,6 +38,9 @@ static char default_environment[] = {
 #else
 const uchar default_environment[] = {
 #endif
+#ifdef	CONFIG_ENV_CALLBACK_LIST_DEFAULT
+	ENV_CALLBACK_VAR "=" CONFIG_ENV_CALLBACK_LIST_DEFAULT "\0"
+#endif
 #ifdef	CONFIG_BOOTARGS
 	"bootargs="	CONFIG_BOOTARGS			"\0"
 #endif
diff --git a/include/environment.h b/include/environment.h
index 4b19f32..6c30215 100644
--- a/include/environment.h
+++ b/include/environment.h
@@ -164,6 +164,8 @@ extern void env_reloc(void);
 
 #ifndef DO_DEPS_ONLY
 
+#include <env_attr.h>
+#include <env_callback.h>
 #include <search.h>
 
 extern struct hsearch_data env_htab;
diff --git a/include/search.h b/include/search.h
index 1e48deb..d68e24a 100644
--- a/include/search.h
+++ b/include/search.h
@@ -47,6 +47,8 @@ typedef enum {
 typedef struct entry {
 	const char *key;
 	char *data;
+	int (*callback)(const char *name, const char *value, enum env_op op,
+		int flags);
 } ENTRY;
 
 /* Opaque type for internal use.  */
@@ -120,6 +122,9 @@ extern int himport_r(struct hsearch_data *__htab,
 		     const char *__env, size_t __size, const char __sep,
 		     int __flag, int nvars, char * const vars[]);
 
+/* Walk the whole table calling the callback on each element */
+extern int hwalk_r(struct hsearch_data *__htab, int (*callback)(ENTRY *));
+
 /* Flags for himport_r(), hexport_r(), hdelete_r(), and hsearch_r() */
 #define H_NOCLEAR	(1 << 0) /* do not clear hash table before importing */
 #define H_FORCE		(1 << 1) /* overwrite read-only/write-once variables */
diff --git a/lib/hashtable.c b/lib/hashtable.c
index 7c6b96c..e922666 100644
--- a/lib/hashtable.c
+++ b/lib/hashtable.c
@@ -54,7 +54,8 @@
 #define	CONFIG_ENV_MAX_ENTRIES 512
 #endif
 
-#include "search.h"
+#include <env_callback.h>
+#include <search.h>
 
 /*
  * [Aho,Sethi,Ullman] Compilers: Principles, Techniques and Tools, 1986
@@ -274,6 +275,17 @@ static inline int _compare_and_overwrite_entry(ENTRY item, ACTION action,
 				return 0;
 			}
 
+			/* If there is a callback, call it */
+			if (htab->table[idx].entry.callback &&
+			    htab->table[idx].entry.callback(item.key,
+			    item.data, env_op_overwrite, flag)) {
+				debug("callback() rejected setting variable "
+					"%s, skipping it!\n", item.key);
+				__set_errno(EINVAL);
+				*retval = NULL;
+				return 0;
+			}
+
 			free(htab->table[idx].entry.data);
 			htab->table[idx].entry.data = strdup(item.data);
 			if (!htab->table[idx].entry.data) {
@@ -398,6 +410,9 @@ int hsearch_r(ENTRY item, ACTION action, ENTRY ** retval,
 
 		++htab->filled;
 
+		/* This is a new entry, so look up a possible callback */
+		env_callback_init(&htab->table[idx].entry);
+
 		/* check for permission */
 		if (htab->change_ok != NULL && htab->change_ok(
 		    &htab->table[idx].entry, item.data, env_op_create, flag)) {
@@ -409,6 +424,18 @@ int hsearch_r(ENTRY item, ACTION action, ENTRY ** retval,
 			return 0;
 		}
 
+		/* If there is a callback, call it */
+		if (htab->table[idx].entry.callback &&
+		    htab->table[idx].entry.callback(item.key, item.data,
+		    env_op_create, flag)) {
+			debug("callback() rejected setting variable "
+				"%s, skipping it!\n", item.key);
+			_hdelete(item.key, htab, &htab->table[idx].entry, idx);
+			__set_errno(EINVAL);
+			*retval = NULL;
+			return 0;
+		}
+
 		/* return new entry */
 		*retval = &htab->table[idx].entry;
 		return 1;
@@ -437,6 +464,7 @@ static void _hdelete(const char *key, struct hsearch_data *htab, ENTRY *ep,
 	debug("hdelete: DELETING key \"%s\"\n", key);
 	free((void *)ep->key);
 	free(ep->data);
+	ep->callback = NULL;
 	htab->table[idx].used = -1;
 
 	--htab->filled;
@@ -466,6 +494,15 @@ int hdelete_r(const char *key, struct hsearch_data *htab, int flag)
 		return 0;
 	}
 
+	/* If there is a callback, call it */
+	if (htab->table[idx].entry.callback &&
+	    htab->table[idx].entry.callback(key, NULL, env_op_delete, flag)) {
+		debug("callback() rejected deleting variable "
+			"%s, skipping it!\n", key);
+		__set_errno(EINVAL);
+		return 0;
+	}
+
 	_hdelete(key, htab, ep, idx);
 
 	return 1;
@@ -838,11 +875,9 @@ int himport_r(struct hsearch_data *htab,
 		e.data = value;
 
 		hsearch_r(e, ENTER, &rv, htab, flag);
-		if (rv == NULL) {
+		if (rv == NULL)
 			printf("himport_r: can't insert \"%s=%s\" into hash table\n",
 				name, value);
-			return 0;
-		}
 
 		debug("INSERT: table %p, filled %d/%d rv %p ==> name=\"%s\" value=\"%s\"\n",
 			htab, htab->filled, htab->size,
@@ -873,3 +908,27 @@ int himport_r(struct hsearch_data *htab,
 	debug("INSERT: done\n");
 	return 1;		/* everything OK */
 }
+
+/*
+ * hwalk_r()
+ */
+
+/*
+ * Walk all of the entries in the hash, calling the callback for each one.
+ * this allows some generic operation to be performed on each element.
+ */
+int hwalk_r(struct hsearch_data *htab, int (*callback)(ENTRY *))
+{
+	int i;
+	int retval;
+
+	for (i = 1; i <= htab->size; ++i) {
+		if (htab->table[i].used > 0) {
+			retval = callback(&htab->table[i].entry);
+			if (retval)
+				return retval;
+		}
+	}
+
+	return 0;
+}
-- 
1.7.11.5

^ permalink raw reply related	[flat|nested] 124+ messages in thread

* [U-Boot] [PATCH v3 08/18] env: Add a command to view callbacks
  2012-11-01 16:39                                       ` [U-Boot] [PATCH v3 0/18] Add environment call-back and flags capability Joe Hershberger
                                                           ` (6 preceding siblings ...)
  2012-11-01 16:39                                         ` [U-Boot] [PATCH v3 07/18] env: Add support for callbacks to environment vars Joe Hershberger
@ 2012-11-01 16:39                                         ` Joe Hershberger
  2012-11-01 16:39                                         ` [U-Boot] [PATCH v3 09/18] env: Add a bootfile env handler Joe Hershberger
                                                           ` (11 subsequent siblings)
  19 siblings, 0 replies; 124+ messages in thread
From: Joe Hershberger @ 2012-11-01 16:39 UTC (permalink / raw)
  To: u-boot

The callbacks can be bound, but are otherwise invisible.  Add a command
to show what callbacks are available.

Signed-off-by: Joe Hershberger <joe.hershberger@ni.com>
---

 README              |  1 +
 common/cmd_nvedit.c | 77 +++++++++++++++++++++++++++++++++++++++++++++++++++++
 2 files changed, 78 insertions(+)

diff --git a/README b/README
index 2834b52..ef19d21 100644
--- a/README
+++ b/README
@@ -806,6 +806,7 @@ The following options need to be configured:
 		CONFIG_CMD_EDITENV	  edit env variable
 		CONFIG_CMD_EEPROM	* EEPROM read/write support
 		CONFIG_CMD_ELF		* bootelf, bootvx
+		CONFIG_CMD_ENV_CALLBACK	* display details about env callbacks
 		CONFIG_CMD_EXPORTENV	* export the environment
 		CONFIG_CMD_EXT2		* ext2 command support
 		CONFIG_CMD_EXT4		* ext4 command support
diff --git a/common/cmd_nvedit.c b/common/cmd_nvedit.c
index a0cdc4b..12949aa 100644
--- a/common/cmd_nvedit.c
+++ b/common/cmd_nvedit.c
@@ -513,6 +513,77 @@ int do_env_ask(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
 }
 #endif
 
+#if defined(CONFIG_CMD_ENV_CALLBACK)
+static int print_static_binding(const char *var_name, const char *callback_name)
+{
+	printf("\t%-20s %-20s\n", var_name, callback_name);
+
+	return 0;
+}
+
+static int print_active_callback(ENTRY *entry)
+{
+	struct env_clbk_tbl *clbkp;
+	int i;
+	int num_callbacks;
+
+	if (entry->callback == NULL)
+		return 0;
+
+	/* look up the callback in the linker-list */
+	num_callbacks = ll_entry_count(struct env_clbk_tbl, env_clbk);
+	for (i = 0, clbkp = ll_entry_start(struct env_clbk_tbl, env_clbk);
+	     i < num_callbacks;
+	     i++, clbkp++) {
+		if (entry->callback == clbkp->callback)
+			break;
+	}
+
+	if (i == num_callbacks)
+		/* this should probably never happen, but just in case... */
+		printf("\t%-20s %p\n", entry->key, entry->callback);
+	else
+		printf("\t%-20s %-20s\n", entry->key, clbkp->name);
+
+	return 0;
+}
+
+/*
+ * Print the callbacks available and what they are bound to
+ */
+int do_env_callback(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
+{
+	struct env_clbk_tbl *clbkp;
+	int i;
+	int num_callbacks;
+
+	/* Print the available callbacks */
+	puts("Available callbacks:\n");
+	puts("\tCallback Name\n");
+	puts("\t-------------\n");
+	num_callbacks = ll_entry_count(struct env_clbk_tbl, env_clbk);
+	for (i = 0, clbkp = ll_entry_start(struct env_clbk_tbl, env_clbk);
+	     i < num_callbacks;
+	     i++, clbkp++)
+		printf("\t%s\n", clbkp->name);
+	puts("\n");
+
+	/* Print the static bindings that may exist */
+	puts("Static callback bindings:\n");
+	printf("\t%-20s %-20s\n", "Variable Name", "Callback Name");
+	printf("\t%-20s %-20s\n", "-------------", "-------------");
+	env_attr_walk(ENV_CALLBACK_LIST_STATIC, print_static_binding);
+	puts("\n");
+
+	/* walk through each variable and print the callback if it has one */
+	puts("Active callback bindings:\n");
+	printf("\t%-20s %-20s\n", "Variable Name", "Callback Name");
+	printf("\t%-20s %-20s\n", "-------------", "-------------");
+	hwalk_r(&env_htab, print_active_callback);
+	return 0;
+}
+#endif
+
 /*
  * Interactively edit an environment variable
  */
@@ -978,6 +1049,9 @@ static cmd_tbl_t cmd_env_sub[] = {
 #if defined(CONFIG_CMD_EDITENV)
 	U_BOOT_CMD_MKENT(edit, 2, 0, do_env_edit, "", ""),
 #endif
+#if defined(CONFIG_CMD_ENV_CALLBACK)
+	U_BOOT_CMD_MKENT(callback, 1, 0, do_env_callback, "", ""),
+#endif
 #if defined(CONFIG_CMD_EXPORTENV)
 	U_BOOT_CMD_MKENT(export, 4, 0, do_env_export, "", ""),
 #endif
@@ -1029,6 +1103,9 @@ U_BOOT_CMD(
 #if defined(CONFIG_CMD_ASKENV)
 	"ask name [message] [size] - ask for environment variable\nenv "
 #endif
+#if defined(CONFIG_CMD_CALLBACKENV)
+	"callback [name] - print callbacks and their associated variables\nenv "
+#endif
 	"default [-f] -a - [forcibly] reset default environment\n"
 	"env default [-f] var [...] - [forcibly] reset variable(s) to their default values\n"
 #if defined(CONFIG_CMD_EDITENV)
-- 
1.7.11.5

^ permalink raw reply related	[flat|nested] 124+ messages in thread

* [U-Boot] [PATCH v3 09/18] env: Add a bootfile env handler
  2012-11-01 16:39                                       ` [U-Boot] [PATCH v3 0/18] Add environment call-back and flags capability Joe Hershberger
                                                           ` (7 preceding siblings ...)
  2012-11-01 16:39                                         ` [U-Boot] [PATCH v3 08/18] env: Add a command to view callbacks Joe Hershberger
@ 2012-11-01 16:39                                         ` Joe Hershberger
  2012-11-01 16:39                                         ` [U-Boot] [PATCH v3 10/18] env: Add a baudrate " Joe Hershberger
                                                           ` (10 subsequent siblings)
  19 siblings, 0 replies; 124+ messages in thread
From: Joe Hershberger @ 2012-11-01 16:39 UTC (permalink / raw)
  To: u-boot

Remove the hard-coded bootfile handler and use a callback instead

Signed-off-by: Joe Hershberger <joe.hershberger@ni.com>
---

 common/cmd_nvedit.c    |  9 ---------
 include/env_callback.h |  1 +
 net/net.c              | 17 +++++++++++++++++
 3 files changed, 18 insertions(+), 9 deletions(-)

diff --git a/common/cmd_nvedit.c b/common/cmd_nvedit.c
index 12949aa..b3d0894 100644
--- a/common/cmd_nvedit.c
+++ b/common/cmd_nvedit.c
@@ -50,9 +50,6 @@
 #include <serial.h>
 #include <linux/stddef.h>
 #include <asm/byteorder.h>
-#if defined(CONFIG_CMD_NET)
-#include <net.h>
-#endif
 
 DECLARE_GLOBAL_DATA_PTR;
 
@@ -327,12 +324,6 @@ int env_change_ok(const ENTRY *item, const char *newval, enum env_op op,
 		load_addr = simple_strtoul(newval, NULL, 16);
 		return 0;
 	}
-#if defined(CONFIG_CMD_NET)
-	else if (strcmp(name, "bootfile") == 0) {
-		copy_filename(BootFile, newval, sizeof(BootFile));
-		return 0;
-	}
-#endif
 	return 0;
 }
 
diff --git a/include/env_callback.h b/include/env_callback.h
index 1a25e3f..caf2cc4 100644
--- a/include/env_callback.h
+++ b/include/env_callback.h
@@ -39,6 +39,7 @@
  * a new assogiation in the ".callbacks" environment variable.
  */
 #define ENV_CALLBACK_LIST_STATIC ENV_CALLBACK_VAR ":callbacks," \
+	"bootfile:bootfile," \
 	CONFIG_ENV_CALLBACK_LIST_STATIC
 
 struct env_clbk_tbl {
diff --git a/net/net.c b/net/net.c
index c1fe00a..65be934 100644
--- a/net/net.c
+++ b/net/net.c
@@ -82,6 +82,7 @@
 
 #include <common.h>
 #include <command.h>
+#include <environment.h>
 #include <net.h>
 #if defined(CONFIG_STATUS_LED)
 #include <miiphy.h>
@@ -208,6 +209,22 @@ static int NetTryCount;
 
 /**********************************************************************/
 
+static int on_bootfile(const char *name, const char *value, enum env_op op,
+	int flags)
+{
+	switch (op) {
+	case env_op_create:
+	case env_op_overwrite:
+		copy_filename(BootFile, value, sizeof(BootFile));
+		break;
+	default:
+		break;
+	}
+
+	return 0;
+}
+U_BOOT_ENV_CALLBACK(bootfile, on_bootfile);
+
 /*
  * Check if autoload is enabled. If so, use either NFS or TFTP to download
  * the boot file.
-- 
1.7.11.5

^ permalink raw reply related	[flat|nested] 124+ messages in thread

* [U-Boot] [PATCH v3 10/18] env: Add a baudrate env handler
  2012-11-01 16:39                                       ` [U-Boot] [PATCH v3 0/18] Add environment call-back and flags capability Joe Hershberger
                                                           ` (8 preceding siblings ...)
  2012-11-01 16:39                                         ` [U-Boot] [PATCH v3 09/18] env: Add a bootfile env handler Joe Hershberger
@ 2012-11-01 16:39                                         ` Joe Hershberger
  2012-11-01 16:39                                         ` [U-Boot] [PATCH v3 11/18] env: Add a loadaddr " Joe Hershberger
                                                           ` (9 subsequent siblings)
  19 siblings, 0 replies; 124+ messages in thread
From: Joe Hershberger @ 2012-11-01 16:39 UTC (permalink / raw)
  To: u-boot

Remove the hard-coded baudrate handler and use a callback instead

Signed-off-by: Joe Hershberger <joe.hershberger@ni.com>
---

 common/cmd_nvedit.c     | 47 ---------------------------------
 drivers/serial/serial.c | 70 +++++++++++++++++++++++++++++++++++++++++++++++++
 include/env_callback.h  |  1 +
 3 files changed, 71 insertions(+), 47 deletions(-)

diff --git a/common/cmd_nvedit.c b/common/cmd_nvedit.c
index b3d0894..49f15f5 100644
--- a/common/cmd_nvedit.c
+++ b/common/cmd_nvedit.c
@@ -78,12 +78,6 @@ ulong save_addr;			/* Default Save Address */
 ulong save_size;			/* Default Save Size (in bytes) */
 
 /*
- * Table with supported baudrates (defined in config_xyz.h)
- */
-static const unsigned long baudrate_table[] = CONFIG_SYS_BAUDRATE_TABLE;
-#define	N_BAUDRATES (sizeof(baudrate_table) / sizeof(baudrate_table[0]))
-
-/*
  * This variable is incremented on each do_env_set(), so it can
  * be used via get_env_id() as an indication, if the environment
  * has changed or not. So it is possible to reread an environment
@@ -274,47 +268,6 @@ int env_change_ok(const ENTRY *item, const char *newval, enum env_op op,
 		}
 	}
 #endif
-	/*
-	 * When we change baudrate, or we are doing an env default -a
-	 * (which will erase all variables prior to calling this),
-	 * we want the baudrate to actually change - for real.
-	 */
-	if (op != env_op_create ||		/* variable exists */
-		(flag & H_NOCLEAR) == 0) {	/* or env is clear */
-		/*
-		 * Switch to new baudrate if new baudrate is supported
-		 */
-		if (strcmp(name, "baudrate") == 0) {
-			int baudrate = simple_strtoul(newval, NULL, 10);
-			int i;
-			for (i = 0; i < N_BAUDRATES; ++i) {
-				if (baudrate == baudrate_table[i])
-					break;
-			}
-			if (i == N_BAUDRATES) {
-				if ((flag & H_FORCE) == 0)
-					printf("## Baudrate %d bps not "
-						"supported\n", 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);
-			gd->baudrate = baudrate;
-#if defined(CONFIG_PPC) || defined(CONFIG_MCF52x2)
-			gd->bd->bi_baudrate = baudrate;
-#endif
-
-			serial_setbrg();
-			udelay(50000);
-			while (getc() != '\r')
-				;
-		}
-	}
 
 	/*
 	 * Some variables should be updated when the corresponding
diff --git a/drivers/serial/serial.c b/drivers/serial/serial.c
index f5f43a6..1f8955a 100644
--- a/drivers/serial/serial.c
+++ b/drivers/serial/serial.c
@@ -22,6 +22,7 @@
  */
 
 #include <common.h>
+#include <environment.h>
 #include <serial.h>
 #include <stdio_dev.h>
 #include <post.h>
@@ -32,6 +33,11 @@ DECLARE_GLOBAL_DATA_PTR;
 
 static struct serial_device *serial_devices;
 static struct serial_device *serial_current;
+/*
+ * Table with supported baudrates (defined in config_xyz.h)
+ */
+static const unsigned long baudrate_table[] = CONFIG_SYS_BAUDRATE_TABLE;
+#define	N_BAUDRATES (sizeof(baudrate_table) / sizeof(baudrate_table[0]))
 
 /**
  * serial_null() - Void registration routine of a serial driver
@@ -46,6 +52,70 @@ static void serial_null(void)
 }
 
 /**
+ * on_baudrate() - Update the actual baudrate when the env var changes
+ *
+ * This will check for a valid baudrate and only apply it if valid.
+ */
+static int on_baudrate(const char *name, const char *value, enum env_op op,
+	int flags)
+{
+	int i;
+	int baudrate;
+
+	switch (op) {
+	case env_op_create:
+	case env_op_overwrite:
+		/*
+		 * Switch to new baudrate if new baudrate is supported
+		 */
+		baudrate = simple_strtoul(value, NULL, 10);
+
+		/* Not actually changing */
+		if (gd->baudrate == baudrate)
+			return 0;
+
+		for (i = 0; i < N_BAUDRATES; ++i) {
+			if (baudrate == baudrate_table[i])
+				break;
+		}
+		if (i == N_BAUDRATES) {
+			if ((flags & H_FORCE) == 0)
+				printf("## Baudrate %d bps not supported\n",
+					baudrate);
+			return 1;
+		}
+		if ((flags & H_INTERACTIVE) != 0) {
+			printf("## Switch baudrate to %d"
+				" bps and press ENTER ...\n", baudrate);
+			udelay(50000);
+		}
+
+		gd->baudrate = baudrate;
+#if defined(CONFIG_PPC) || defined(CONFIG_MCF52x2)
+		gd->bd->bi_baudrate = baudrate;
+#endif
+
+		serial_setbrg();
+
+		udelay(50000);
+
+		if ((flags & H_INTERACTIVE) != 0)
+			while (1) {
+				if (getc() == '\r')
+					break;
+			}
+
+		return 0;
+	case env_op_delete:
+		printf("## Baudrate may not be deleted\n");
+		return 1;
+	default:
+		return 0;
+	}
+}
+U_BOOT_ENV_CALLBACK(baudrate, on_baudrate);
+
+/**
  * serial_initfunc() - Forward declare of driver registration routine
  * @name:	Name of the real driver registration routine.
  *
diff --git a/include/env_callback.h b/include/env_callback.h
index caf2cc4..c3e800a 100644
--- a/include/env_callback.h
+++ b/include/env_callback.h
@@ -39,6 +39,7 @@
  * a new assogiation in the ".callbacks" environment variable.
  */
 #define ENV_CALLBACK_LIST_STATIC ENV_CALLBACK_VAR ":callbacks," \
+	"baudrate:baudrate," \
 	"bootfile:bootfile," \
 	CONFIG_ENV_CALLBACK_LIST_STATIC
 
-- 
1.7.11.5

^ permalink raw reply related	[flat|nested] 124+ messages in thread

* [U-Boot] [PATCH v3 11/18] env: Add a loadaddr env handler
  2012-11-01 16:39                                       ` [U-Boot] [PATCH v3 0/18] Add environment call-back and flags capability Joe Hershberger
                                                           ` (9 preceding siblings ...)
  2012-11-01 16:39                                         ` [U-Boot] [PATCH v3 10/18] env: Add a baudrate " Joe Hershberger
@ 2012-11-01 16:39                                         ` Joe Hershberger
  2012-11-01 16:39                                         ` [U-Boot] [PATCH v3 12/18] env: Add a console " Joe Hershberger
                                                           ` (8 subsequent siblings)
  19 siblings, 0 replies; 124+ messages in thread
From: Joe Hershberger @ 2012-11-01 16:39 UTC (permalink / raw)
  To: u-boot

Remove the hard-coded loadaddr handler and use a callback instead

Signed-off-by: Joe Hershberger <joe.hershberger@ni.com>
---

 common/cmd_nvedit.c    | 12 ------------
 common/image.c         | 21 +++++++++++++++++++++
 include/env_callback.h |  1 +
 3 files changed, 22 insertions(+), 12 deletions(-)

diff --git a/common/cmd_nvedit.c b/common/cmd_nvedit.c
index 49f15f5..7b48560 100644
--- a/common/cmd_nvedit.c
+++ b/common/cmd_nvedit.c
@@ -73,10 +73,6 @@ SPI_FLASH|NVRAM|MMC|FAT|REMOTE} or CONFIG_ENV_IS_NOWHERE
  */
 #define	MAX_ENV_SIZE	(1 << 20)	/* 1 MiB */
 
-ulong load_addr = CONFIG_SYS_LOAD_ADDR;	/* Default Load Address */
-ulong save_addr;			/* Default Save Address */
-ulong save_size;			/* Default Save Size (in bytes) */
-
 /*
  * This variable is incremented on each do_env_set(), so it can
  * be used via get_env_id() as an indication, if the environment
@@ -269,14 +265,6 @@ int env_change_ok(const ENTRY *item, const char *newval, enum env_op op,
 	}
 #endif
 
-	/*
-	 * Some variables should be updated when the corresponding
-	 * entry in the environment is changed
-	 */
-	if (strcmp(name, "loadaddr") == 0) {
-		load_addr = simple_strtoul(newval, NULL, 16);
-		return 0;
-	}
 	return 0;
 }
 
diff --git a/common/image.c b/common/image.c
index 60428c7..664df2d 100644
--- a/common/image.c
+++ b/common/image.c
@@ -43,6 +43,7 @@
 #include <rtc.h>
 #endif
 
+#include <environment.h>
 #include <image.h>
 
 #if defined(CONFIG_FIT) || defined(CONFIG_OF_LIBFDT)
@@ -416,6 +417,26 @@ static const image_header_t *image_get_ramdisk(ulong rd_addr, uint8_t arch,
 /* Shared dual-format routines */
 /*****************************************************************************/
 #ifndef USE_HOSTCC
+ulong load_addr = CONFIG_SYS_LOAD_ADDR;	/* Default Load Address */
+ulong save_addr;			/* Default Save Address */
+ulong save_size;			/* Default Save Size (in bytes) */
+
+static int on_loadaddr(const char *name, const char *value, enum env_op op,
+	int flags)
+{
+	switch (op) {
+	case env_op_create:
+	case env_op_overwrite:
+		load_addr = simple_strtoul(value, NULL, 16);
+		break;
+	default:
+		break;
+	}
+
+	return 0;
+}
+U_BOOT_ENV_CALLBACK(loadaddr, on_loadaddr);
+
 ulong getenv_bootm_low(void)
 {
 	char *s = getenv("bootm_low");
diff --git a/include/env_callback.h b/include/env_callback.h
index c3e800a..309ff9b 100644
--- a/include/env_callback.h
+++ b/include/env_callback.h
@@ -41,6 +41,7 @@
 #define ENV_CALLBACK_LIST_STATIC ENV_CALLBACK_VAR ":callbacks," \
 	"baudrate:baudrate," \
 	"bootfile:bootfile," \
+	"loadaddr:loadaddr," \
 	CONFIG_ENV_CALLBACK_LIST_STATIC
 
 struct env_clbk_tbl {
-- 
1.7.11.5

^ permalink raw reply related	[flat|nested] 124+ messages in thread

* [U-Boot] [PATCH v3 12/18] env: Add a console env handler
  2012-11-01 16:39                                       ` [U-Boot] [PATCH v3 0/18] Add environment call-back and flags capability Joe Hershberger
                                                           ` (10 preceding siblings ...)
  2012-11-01 16:39                                         ` [U-Boot] [PATCH v3 11/18] env: Add a loadaddr " Joe Hershberger
@ 2012-11-01 16:39                                         ` Joe Hershberger
  2012-11-01 16:39                                         ` [U-Boot] [PATCH v3 13/18] env: Add a silent " Joe Hershberger
                                                           ` (7 subsequent siblings)
  19 siblings, 0 replies; 124+ messages in thread
From: Joe Hershberger @ 2012-11-01 16:39 UTC (permalink / raw)
  To: u-boot

Remove the hard-coded console handler and use a callback instead

Signed-off-by: Joe Hershberger <joe.hershberger@ni.com>
---

 common/cmd_nvedit.c    | 33 +++------------------------------
 common/console.c       | 44 ++++++++++++++++++++++++++++++++++++++++++++
 include/env_callback.h |  1 +
 3 files changed, 48 insertions(+), 30 deletions(-)

diff --git a/common/cmd_nvedit.c b/common/cmd_nvedit.c
index 7b48560..9cb6629 100644
--- a/common/cmd_nvedit.c
+++ b/common/cmd_nvedit.c
@@ -47,7 +47,6 @@
 #include <errno.h>
 #include <malloc.h>
 #include <watchdog.h>
-#include <serial.h>
 #include <linux/stddef.h>
 #include <asm/byteorder.h>
 
@@ -205,10 +204,9 @@ static int do_env_grep(cmd_tbl_t *cmdtp, int flag,
 int env_change_ok(const ENTRY *item, const char *newval, enum env_op op,
 	int flag)
 {
-	int   console = -1;
+#ifndef CONFIG_ENV_OVERWRITE
 	const char *name;
-#if !defined(CONFIG_ENV_OVERWRITE) && defined(CONFIG_OVERWRITE_ETHADDR_ONCE) \
-&& defined(CONFIG_ETHADDR)
+#if defined(CONFIG_OVERWRITE_ETHADDR_ONCE) && defined(CONFIG_ETHADDR)
 	const char *oldval = NULL;
 
 	if (op != env_op_create)
@@ -216,36 +214,11 @@ int env_change_ok(const ENTRY *item, const char *newval, enum env_op op,
 #endif
 
 	name = item->key;
+#endif
 
 	/* Default value for NULL to protect string-manipulating functions */
 	newval = newval ? : "";
 
-	/* Check for console redirection */
-	if (strcmp(name, "stdin") == 0)
-		console = stdin;
-	else if (strcmp(name, "stdout") == 0)
-		console = stdout;
-	else if (strcmp(name, "stderr") == 0)
-		console = stderr;
-
-	if (console != -1) {
-		if ((newval == NULL) || (*newval == '\0')) {
-			/* We cannot delete stdin/stdout/stderr */
-			if ((flag & H_FORCE) == 0)
-				printf("Can't delete \"%s\"\n", name);
-			return 1;
-		}
-
-#ifdef CONFIG_CONSOLE_MUX
-		if (iomux_doenv(console, newval))
-			return 1;
-#else
-		/* Try assigning specified device */
-		if (console_assign(console, newval) < 0)
-			return 1;
-#endif /* CONFIG_CONSOLE_MUX */
-	}
-
 #ifndef CONFIG_ENV_OVERWRITE
 	/*
 	 * Some variables like "ethaddr" and "serial#" can be set only once and
diff --git a/common/console.c b/common/console.c
index 1177f7d..713bd34 100644
--- a/common/console.c
+++ b/common/console.c
@@ -24,11 +24,55 @@
 #include <common.h>
 #include <stdarg.h>
 #include <malloc.h>
+#include <serial.h>
 #include <stdio_dev.h>
 #include <exports.h>
+#include <environment.h>
 
 DECLARE_GLOBAL_DATA_PTR;
 
+static int on_console(const char *name, const char *value, enum env_op op,
+	int flags)
+{
+	int console = -1;
+
+	/* Check for console redirection */
+	if (strcmp(name, "stdin") == 0)
+		console = stdin;
+	else if (strcmp(name, "stdout") == 0)
+		console = stdout;
+	else if (strcmp(name, "stderr") == 0)
+		console = stderr;
+
+	/* if not actually setting a console variable, we don't care */
+	if (console == -1)
+		return 0;
+
+	switch (op) {
+	case env_op_create:
+	case env_op_overwrite:
+
+#ifdef CONFIG_CONSOLE_MUX
+		if (iomux_doenv(console, value))
+			return 1;
+#else
+		/* Try assigning specified device */
+		if (console_assign(console, value) < 0)
+			return 1;
+#endif /* CONFIG_CONSOLE_MUX */
+		return 0;
+
+	case env_op_delete:
+		if ((flags & H_FORCE) == 0)
+			printf("Can't delete \"%s\"\n", name);
+		return 1;
+
+	default:
+		return 0;
+	}
+}
+U_BOOT_ENV_CALLBACK(console, on_console);
+
 #ifdef CONFIG_SYS_CONSOLE_IS_IN_ENV
 /*
  * if overwrite_console returns 1, the stdin, stderr and stdout
diff --git a/include/env_callback.h b/include/env_callback.h
index 309ff9b..a614744 100644
--- a/include/env_callback.h
+++ b/include/env_callback.h
@@ -42,6 +42,7 @@
 	"baudrate:baudrate," \
 	"bootfile:bootfile," \
 	"loadaddr:loadaddr," \
+	"stdin:console,stdout:console,stderr:console," \
 	CONFIG_ENV_CALLBACK_LIST_STATIC
 
 struct env_clbk_tbl {
-- 
1.7.11.5

^ permalink raw reply related	[flat|nested] 124+ messages in thread

* [U-Boot] [PATCH v3 13/18] env: Add a silent env handler
  2012-11-01 16:39                                       ` [U-Boot] [PATCH v3 0/18] Add environment call-back and flags capability Joe Hershberger
                                                           ` (11 preceding siblings ...)
  2012-11-01 16:39                                         ` [U-Boot] [PATCH v3 12/18] env: Add a console " Joe Hershberger
@ 2012-11-01 16:39                                         ` Joe Hershberger
  2012-11-01 16:39                                         ` [U-Boot] [PATCH v3 14/18] env: Add environment variable flags Joe Hershberger
                                                           ` (6 subsequent siblings)
  19 siblings, 0 replies; 124+ messages in thread
From: Joe Hershberger @ 2012-11-01 16:39 UTC (permalink / raw)
  To: u-boot

The silent variable now updates the global data flag anytime it is
changed as well as after the env relocation (in case its value is
different from the default env in such cases as NAND env)

Signed-off-by: Joe Hershberger <joe.hershberger@ni.com>
---

 common/console.c       | 23 +++++++++++++++++++++++
 doc/README.silent      | 14 ++++++++++----
 include/env_callback.h |  7 +++++++
 3 files changed, 40 insertions(+), 4 deletions(-)

diff --git a/common/console.c b/common/console.c
index 713bd34..0e51d67 100644
--- a/common/console.c
+++ b/common/console.c
@@ -73,6 +73,29 @@ static int on_console(const char *name, const char *value, enum env_op op,
 }
 U_BOOT_ENV_CALLBACK(console, on_console);
 
+#ifdef CONFIG_SILENT_CONSOLE
+static int on_silent(const char *name, const char *value, enum env_op op,
+	int flags)
+{
+#ifndef CONFIG_SILENT_CONSOLE_UPDATE_ON_SET
+	if (flags & H_INTERACTIVE)
+		return 0;
+#endif
+#ifndef CONFIG_SILENT_CONSOLE_UPDATE_ON_RELOC
+	if ((flags & H_INTERACTIVE) == 0)
+		return 0;
+#endif
+
+	if (value != NULL)
+		gd->flags |= GD_FLG_SILENT;
+	else
+		gd->flags &= ~GD_FLG_SILENT;
+
+	return 0;
+}
+U_BOOT_ENV_CALLBACK(silent, on_silent);
+#endif
+
 #ifdef CONFIG_SYS_CONSOLE_IS_IN_ENV
 /*
  * if overwrite_console returns 1, the stdin, stderr and stdout
diff --git a/doc/README.silent b/doc/README.silent
index a26e3df..70202ce 100644
--- a/doc/README.silent
+++ b/doc/README.silent
@@ -1,9 +1,15 @@
 The config option CONFIG_SILENT_CONSOLE can be used to quiet messages
 on the console.  If the option has been enabled, the output can be
-silenced by setting the environment variable "silent".  The variable
-is latched into the global data at an early stage in the boot process
-so deleting it with "setenv" will not take effect until the system is
-restarted.
+silenced by setting the environment variable "silent".
+
+- CONFIG_SILENT_CONSOLE_UPDATE_ON_SET
+	When the "silent" variable is changed with env set, the change
+	will take effect immediately.
+
+- CONFIG_SILENT_CONSOLE_UPDATE_ON_RELOC
+	Some environments are not available until relocation (e.g. NAND)
+	so this will make the value in the flash env take effect at
+	relocation.
 
 The following actions are taken if "silent" is set at boot time:
 
diff --git a/include/env_callback.h b/include/env_callback.h
index a614744..d0e0e00 100644
--- a/include/env_callback.h
+++ b/include/env_callback.h
@@ -34,6 +34,12 @@
 #define CONFIG_ENV_CALLBACK_LIST_STATIC
 #endif
 
+#ifdef CONFIG_SILENT_CONSOLE
+#define SILENT_CALLBACK "silent:silent,"
+#else
+#define SILENT_CALLBACK
+#endif
+
 /*
  * This list of callback bindings is static, but may be overridden by defining
  * a new assogiation in the ".callbacks" environment variable.
@@ -42,6 +48,7 @@
 	"baudrate:baudrate," \
 	"bootfile:bootfile," \
 	"loadaddr:loadaddr," \
+	SILENT_CALLBACK \
 	"stdin:console,stdout:console,stderr:console," \
 	CONFIG_ENV_CALLBACK_LIST_STATIC
 
-- 
1.7.11.5

^ permalink raw reply related	[flat|nested] 124+ messages in thread

* [U-Boot] [PATCH v3 14/18] env: Add environment variable flags
  2012-11-01 16:39                                       ` [U-Boot] [PATCH v3 0/18] Add environment call-back and flags capability Joe Hershberger
                                                           ` (12 preceding siblings ...)
  2012-11-01 16:39                                         ` [U-Boot] [PATCH v3 13/18] env: Add a silent " Joe Hershberger
@ 2012-11-01 16:39                                         ` Joe Hershberger
  2012-11-01 16:39                                         ` [U-Boot] [PATCH v3 15/18] tools/env: Add environment variable flags support Joe Hershberger
                                                           ` (5 subsequent siblings)
  19 siblings, 0 replies; 124+ messages in thread
From: Joe Hershberger @ 2012-11-01 16:39 UTC (permalink / raw)
  To: u-boot

Currently just validates variable types as decimal, hexidecimal,
boolean, ip address, and mac address.

If the entry is not found in the env ".flags", then look in the static
one. This allows the env to override the static definitions, but prevents
the need to have every definition in the environment distracting you.

Signed-off-by: Joe Hershberger <joe.hershberger@ni.com>
---

 README                 |  37 ++++++
 common/Makefile        |   2 +
 common/cmd_nvedit.c    |  53 +--------
 common/env_common.c    |   2 +-
 common/env_flags.c     | 314 +++++++++++++++++++++++++++++++++++++++++++++++++
 include/env_callback.h |   2 +
 include/env_default.h  |   3 +
 include/env_flags.h    |  76 ++++++++++++
 include/environment.h  |   9 +-
 include/search.h       |   1 +
 lib/hashtable.c        |   4 +
 11 files changed, 442 insertions(+), 61 deletions(-)
 create mode 100644 common/env_flags.c
 create mode 100644 include/env_flags.h

diff --git a/README b/README
index ef19d21..315ed36 100644
--- a/README
+++ b/README
@@ -2156,6 +2156,11 @@ CBFS (Coreboot Filesystem) support
 		serial# is unaffected by this, i. e. it remains
 		read-only.]
 
+		The same can be accomplished in a more flexible way
+		for any variable by configuring the type of access
+		to allow for those variables in the ".flags" variable
+		or define CONFIG_ENV_FLAGS_LIST_STATIC.
+
 - Protected RAM:
 		CONFIG_PRAM
 
@@ -3007,6 +3012,38 @@ Configuration Settings:
 	cases. This setting can be used to tune behaviour; see
 	lib/hashtable.c for details.
 
+- CONFIG_ENV_FLAGS_LIST_DEFAULT
+- CONFIG_ENV_FLAGS_LIST_STATIC
+	Enable validation of the values given to enviroment variables when
+	calling env set.  Variables can be restricted to only decimal,
+	hexadecimal, or boolean.  If CONFIG_CMD_NET is also defined,
+	the variables can also be restricted to IP address or MAC address.
+
+	The format of the list is:
+		type_attribute = [s|d|x|b|i|m]
+		attributes = type_attribute
+		entry = variable_name[:attributes]
+		list = entry[,list]
+
+	The type attributes are:
+		s - String (default)
+		d - Decimal
+		x - Hexadecimal
+		b - Boolean ([1yYtT|0nNfF])
+		i - IP address
+		m - MAC address
+
+	- CONFIG_ENV_FLAGS_LIST_DEFAULT
+		Define this to a list (string) to define the ".flags"
+		envirnoment variable in the default or embedded environment.
+
+	- CONFIG_ENV_FLAGS_LIST_STATIC
+		Define this to a list (string) to define validation that
+		should be done if an entry is not found in the ".flags"
+		environment variable.  To override a setting in the static
+		list, simply add an entry for the same variable name to the
+		".flags" variable.
+
 The following definitions that deal with the placement and management
 of environment data (variable area); in general, we support the
 following configurations:
diff --git a/common/Makefile b/common/Makefile
index af6e8f9..ef2bd00 100644
--- a/common/Makefile
+++ b/common/Makefile
@@ -46,6 +46,7 @@ COBJS-y += cmd_version.o
 COBJS-y += env_attr.o
 COBJS-y += env_callback.o
 COBJS-y += env_common.o
+COBJS-y += env_flags.o
 COBJS-$(CONFIG_ENV_IS_IN_DATAFLASH) += env_dataflash.o
 COBJS-$(CONFIG_ENV_IS_IN_EEPROM) += env_eeprom.o
 XCOBJS-$(CONFIG_ENV_IS_EMBEDDED) += env_embedded.o
@@ -202,6 +203,7 @@ COBJS-$(CONFIG_SPL_NET_SUPPORT) += cmd_nvedit.o
 COBJS-$(CONFIG_SPL_NET_SUPPORT) += env_attr.o
 COBJS-$(CONFIG_SPL_NET_SUPPORT) += env_callback.o
 COBJS-$(CONFIG_SPL_NET_SUPPORT) += env_common.o
+COBJS-$(CONFIG_SPL_NET_SUPPORT) += env_flags.o
 COBJS-$(CONFIG_SPL_NET_SUPPORT) += env_nowhere.o
 COBJS-$(CONFIG_SPL_NET_SUPPORT) += miiphyutil.o
 endif
diff --git a/common/cmd_nvedit.c b/common/cmd_nvedit.c
index 9cb6629..cadf0df 100644
--- a/common/cmd_nvedit.c
+++ b/common/cmd_nvedit.c
@@ -191,60 +191,9 @@ static int do_env_grep(cmd_tbl_t *cmdtp, int flag,
 #endif /* CONFIG_SPL_BUILD */
 
 /*
- * Perform 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 instead.
- * Also called as a callback function by himport_r().
- * Returns 0 in case of success, 1 in case of failure.
- * When (flag & H_FORCE) is set, do not print out any error message and force
- * overwriting of write-once variables.
- */
-
-int env_change_ok(const ENTRY *item, const char *newval, enum env_op op,
-	int flag)
-{
-#ifndef CONFIG_ENV_OVERWRITE
-	const char *name;
-#if defined(CONFIG_OVERWRITE_ETHADDR_ONCE) && defined(CONFIG_ETHADDR)
-	const char *oldval = NULL;
-
-	if (op != env_op_create)
-		oldval = item->data;
-#endif
-
-	name = item->key;
-#endif
-
-	/* 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
-
-	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;
diff --git a/common/env_common.c b/common/env_common.c
index a86f061..b711337 100644
--- a/common/env_common.c
+++ b/common/env_common.c
@@ -40,7 +40,7 @@ DECLARE_GLOBAL_DATA_PTR;
 #include <env_default.h>
 
 struct hsearch_data env_htab = {
-	.change_ok = env_change_ok,
+	.change_ok = env_flags_validate,
 };
 
 static uchar __env_get_char_spec(int index)
diff --git a/common/env_flags.c b/common/env_flags.c
new file mode 100644
index 0000000..2292569
--- /dev/null
+++ b/common/env_flags.c
@@ -0,0 +1,314 @@
+/*
+ * (C) Copyright 2012
+ * Joe Hershberger, National Instruments, joe.hershberger at 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
+ */
+
+#include <linux/string.h>
+#include <linux/ctype.h>
+
+#include <common.h>
+#include <environment.h>
+
+#ifdef CONFIG_CMD_NET
+#define ENV_FLAGS_NET_VARTYPE_REPS "im"
+#else
+#define ENV_FLAGS_NET_VARTYPE_REPS ""
+#endif
+
+static const char env_flags_vartype_rep[] = "sdxb" ENV_FLAGS_NET_VARTYPE_REPS;
+
+/*
+ * Parse the flags string from a .flags attribute list into the vartype enum.
+ */
+enum env_flags_vartype env_flags_parse_vartype(const char *flags)
+{
+	char *type = strchr(env_flags_vartype_rep,
+		flags[ENV_FLAGS_VARTYPE_LOC]);
+
+	if (type != NULL)
+		return (enum env_flags_vartype)
+			(type - &env_flags_vartype_rep[0]);
+
+	printf("## Warning: Unknown environment variable type '%c'\n",
+		flags[ENV_FLAGS_VARTYPE_LOC]);
+	return env_flags_vartype_string;
+}
+
+static inline int is_hex_prefix(const char *value)
+{
+	return value[0] == '0' && (value[1] == 'x' || value[1] == 'X');
+}
+
+static void skip_num(int hex, const char *value, const char **end,
+	int max_digits)
+{
+	int i;
+
+	if (hex && is_hex_prefix(value))
+		value += 2;
+
+	for (i = max_digits; i != 0; i--) {
+		if (hex && !isxdigit(*value))
+			break;
+		if (!hex && !isdigit(*value))
+			break;
+		value++;
+	}
+	if (end != NULL)
+		*end = value;
+}
+
+/*
+ * Based on the declared type enum, validate that the value string complies
+ * with that format
+ */
+static int _env_flags_validate_type(const char *value,
+	enum env_flags_vartype type)
+{
+	const char *end;
+#ifdef CONFIG_CMD_NET
+	const char *cur;
+	int i;
+#endif
+
+	switch (type) {
+	case env_flags_vartype_string:
+		break;
+	case env_flags_vartype_decimal:
+		skip_num(0, value, &end, -1);
+		if (*end != '\0')
+			return -1;
+		break;
+	case env_flags_vartype_hex:
+		skip_num(1, value, &end, -1);
+		if (*end != '\0')
+			return -1;
+		if (value + 2 == end && is_hex_prefix(value))
+			return -1;
+		break;
+	case env_flags_vartype_bool:
+		if (value[0] != '1' && value[0] != 'y' && value[0] != 't' &&
+		    value[0] != 'Y' && value[0] != 'T' &&
+		    value[0] != '0' && value[0] != 'n' && value[0] != 'f' &&
+		    value[0] != 'N' && value[0] != 'F')
+			return -1;
+		if (value[1] != '\0')
+			return -1;
+		break;
+#ifdef CONFIG_CMD_NET
+	case env_flags_vartype_ipaddr:
+		cur = value;
+		for (i = 0; i < 4; i++) {
+			skip_num(0, cur, &end, 3);
+			if (cur == end)
+				return -1;
+			if (i != 3 && *end != '.')
+				return -1;
+			if (i == 3 && *end != '\0')
+				return -1;
+			cur = end + 1;
+		}
+		break;
+	case env_flags_vartype_macaddr:
+		cur = value;
+		for (i = 0; i < 6; i++) {
+			skip_num(1, cur, &end, 2);
+			if (cur == end)
+				return -1;
+			if (cur + 2 == end && is_hex_prefix(cur))
+				return -1;
+			if (i != 5 && *end != ':')
+				return -1;
+			if (i == 5 && *end != '\0')
+				return -1;
+			cur = end + 1;
+		}
+		break;
+#endif
+	case env_flags_vartype_end:
+		return -1;
+	}
+
+	/* OK */
+	return 0;
+}
+
+/*
+ * Look for flags in a provided list and failing that the static list
+ */
+static inline int env_flags_lookup(const char *flags_list, const char *name,
+	char *flags)
+{
+	int ret = 1;
+
+	if (!flags)
+		/* bad parameter */
+		return -1;
+
+	/* try the env first */
+	if (flags_list)
+		ret = env_attr_lookup(flags_list, name, flags);
+
+	if (ret != 0)
+		/* if not found in the env, look in the static list */
+		ret = env_attr_lookup(ENV_FLAGS_LIST_STATIC, name, flags);
+
+	return ret;
+}
+
+/*
+ * Parse the flag charachters from the .flags attribute list into the binary
+ * form to be stored in the environment entry->flags field.
+ */
+static int env_parse_flags_to_bin(const char *flags)
+{
+	return env_flags_parse_vartype(flags) & ENV_FLAGS_VARTYPE_BIN_MASK;
+}
+
+/*
+ * Look for possible flags for a newly added variable
+ * This is called specifically when the variable did not exist in the hash
+ * previously, so the blanket update did not find this variable.
+ */
+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;
+
+	/* look in the ".flags" and static for a reference to this variable */
+	ret = env_flags_lookup(flags_list, var_name, flags);
+
+	/* if any flags were found, set the binary form to the entry */
+	if (!ret && strlen(flags))
+		var_entry->flags = env_parse_flags_to_bin(flags);
+}
+
+/*
+ * Called on each existing env var prior to the blanket update since removing
+ * a flag in the flag list should remove its flags.
+ */
+static int clear_flags(ENTRY *entry)
+{
+	entry->flags = 0;
+
+	return 0;
+}
+
+/*
+ * Call for each element in the list that defines flags for a variable
+ */
+static int set_flags(const char *name, const char *value)
+{
+	ENTRY e, *ep;
+
+	e.key	= name;
+	e.data	= NULL;
+	hsearch_r(e, FIND, &ep, &env_htab, 0);
+
+	/* does the env variable actually exist? */
+	if (ep != NULL) {
+		/* the flag list is empty, so clear the flags */
+		if (value == NULL || strlen(value) == 0)
+			ep->flags = 0;
+		else
+			/* assign the requested flags */
+			ep->flags = env_parse_flags_to_bin(value);
+	}
+
+	return 0;
+}
+
+static int on_flags(const char *name, const char *value, enum env_op op,
+	int flags)
+{
+	/* remove all flags */
+	hwalk_r(&env_htab, clear_flags);
+
+	/* configure any static flags */
+	env_attr_walk(ENV_FLAGS_LIST_STATIC, set_flags);
+	/* configure any dynamic flags */
+	env_attr_walk(value, set_flags);
+
+	return 0;
+}
+U_BOOT_ENV_CALLBACK(flags, on_flags);
+
+/*
+ * Perform consistency checking before creating, overwriting, or deleting an
+ * environment variable. Called as a callback function by hsearch_r() and
+ * hdelete_r(). Returns 0 in case of success, 1 in case of failure.
+ * When (flag & H_FORCE) is set, do not print out any error message and force
+ * overwriting of write-once variables.
+ */
+
+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;
+		type = (enum env_flags_vartype)
+			(ENV_FLAGS_VARTYPE_BIN_MASK & item->flags);
+		if (_env_flags_validate_type(newval, type) < 0) {
+			printf("## Error: flags type check failure for "
+				"\"%s\" <= \"%s\" (type: %c)\n",
+				name, newval, env_flags_vartype_rep[type]);
+			return -1;
+		}
+	}
+
+	return 0;
+}
diff --git a/include/env_callback.h b/include/env_callback.h
index d0e0e00..1d8bb0e 100644
--- a/include/env_callback.h
+++ b/include/env_callback.h
@@ -24,6 +24,7 @@
 #ifndef __ENV_CALLBACK_H__
 #define __ENV_CALLBACK_H__
 
+#include <env_flags.h>
 #include <linker_lists.h>
 #include <search.h>
 
@@ -45,6 +46,7 @@
  * a new assogiation in the ".callbacks" environment variable.
  */
 #define ENV_CALLBACK_LIST_STATIC ENV_CALLBACK_VAR ":callbacks," \
+	ENV_FLAGS_VAR ":flags," \
 	"baudrate:baudrate," \
 	"bootfile:bootfile," \
 	"loadaddr:loadaddr," \
diff --git a/include/env_default.h b/include/env_default.h
index cff378d..40a0011 100644
--- a/include/env_default.h
+++ b/include/env_default.h
@@ -41,6 +41,9 @@ const uchar default_environment[] = {
 #ifdef	CONFIG_ENV_CALLBACK_LIST_DEFAULT
 	ENV_CALLBACK_VAR "=" CONFIG_ENV_CALLBACK_LIST_DEFAULT "\0"
 #endif
+#ifdef	CONFIG_ENV_FLAGS_LIST_DEFAULT
+	ENV_FLAGS_VAR "=" CONFIG_ENV_FLAGS_LIST_DEFAULT "\0"
+#endif
 #ifdef	CONFIG_BOOTARGS
 	"bootargs="	CONFIG_BOOTARGS			"\0"
 #endif
diff --git a/include/env_flags.h b/include/env_flags.h
new file mode 100644
index 0000000..bf25f27
--- /dev/null
+++ b/include/env_flags.h
@@ -0,0 +1,76 @@
+/*
+ * (C) Copyright 2012
+ * Joe Hershberger, National Instruments, joe.hershberger at 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
+ */
+
+#ifndef __ENV_FLAGS_H__
+#define __ENV_FLAGS_H__
+
+enum env_flags_vartype {
+	env_flags_vartype_string,
+	env_flags_vartype_decimal,
+	env_flags_vartype_hex,
+	env_flags_vartype_bool,
+#ifdef CONFIG_CMD_NET
+	env_flags_vartype_ipaddr,
+	env_flags_vartype_macaddr,
+#endif
+	env_flags_vartype_end
+};
+
+#define ENV_FLAGS_VAR ".flags"
+#define ENV_FLAGS_ATTR_MAX_LEN 2
+#define ENV_FLAGS_VARTYPE_LOC 0
+
+#ifndef CONFIG_ENV_FLAGS_LIST_STATIC
+#define CONFIG_ENV_FLAGS_LIST_STATIC ""
+#endif
+
+#define ENV_FLAGS_LIST_STATIC \
+	CONFIG_ENV_FLAGS_LIST_STATIC
+
+/*
+ * Parse the flags string from a .flags attribute list into the vartype enum.
+ */
+enum env_flags_vartype env_flags_parse_vartype(const char *flags);
+
+#include <search.h>
+
+/*
+ * When adding a variable to the environment, initialize the flags for that
+ * variable.
+ */
+void env_flags_init(ENTRY *var_entry);
+
+/*
+ * Validate the newval for to conform with the requirements defined by its flags
+ */
+int env_flags_validate(const ENTRY *item, const char *newval, enum env_op op,
+	int flag);
+
+/*
+ * These are the binary flags used in the environment entry->flags variable to
+ * decribe properties of veriables in the table
+ */
+#define ENV_FLAGS_VARTYPE_BIN_MASK	0x00000007
+/* The actual variable type values use the enum value (within the mask) */
+
+#endif /* __ENV_FLAGS_H__ */
diff --git a/include/environment.h b/include/environment.h
index 6c30215..00e59ba 100644
--- a/include/environment.h
+++ b/include/environment.h
@@ -166,6 +166,7 @@ extern void env_reloc(void);
 
 #include <env_attr.h>
 #include <env_callback.h>
+#include <env_flags.h>
 #include <search.h>
 
 extern struct hsearch_data env_htab;
@@ -189,14 +190,6 @@ int set_default_vars(int nvars, char * const vars[]);
 /* Import from binary representation into hash table */
 int env_import(const char *buf, int check);
 
-/*
- * Check if variable "item" can be changed to newval
- * When (flag & H_FORCE) is set, it does not print out any error
- * message and forces overwriting of write-once variables.
- */
-int env_change_ok(const ENTRY *item, const char *newval, enum env_op op,
-	int flag);
-
 #endif /* DO_DEPS_ONLY */
 
 #endif /* _ENVIRONMENT_H_ */
diff --git a/include/search.h b/include/search.h
index d68e24a..13d3be6 100644
--- a/include/search.h
+++ b/include/search.h
@@ -49,6 +49,7 @@ typedef struct entry {
 	char *data;
 	int (*callback)(const char *name, const char *value, enum env_op op,
 		int flags);
+	int flags;
 } ENTRY;
 
 /* Opaque type for internal use.  */
diff --git a/lib/hashtable.c b/lib/hashtable.c
index e922666..07ebfb2 100644
--- a/lib/hashtable.c
+++ b/lib/hashtable.c
@@ -55,6 +55,7 @@
 #endif
 
 #include <env_callback.h>
+#include <env_flags.h>
 #include <search.h>
 
 /*
@@ -412,6 +413,8 @@ int hsearch_r(ENTRY item, ACTION action, ENTRY ** retval,
 
 		/* This is a new entry, so look up a possible callback */
 		env_callback_init(&htab->table[idx].entry);
+		/* Also look for flags */
+		env_flags_init(&htab->table[idx].entry);
 
 		/* check for permission */
 		if (htab->change_ok != NULL && htab->change_ok(
@@ -465,6 +468,7 @@ static void _hdelete(const char *key, struct hsearch_data *htab, ENTRY *ep,
 	free((void *)ep->key);
 	free(ep->data);
 	ep->callback = NULL;
+	ep->flags = 0;
 	htab->table[idx].used = -1;
 
 	--htab->filled;
-- 
1.7.11.5

^ permalink raw reply related	[flat|nested] 124+ messages in thread

* [U-Boot] [PATCH v3 15/18] tools/env: Add environment variable flags support
  2012-11-01 16:39                                       ` [U-Boot] [PATCH v3 0/18] Add environment call-back and flags capability Joe Hershberger
                                                           ` (13 preceding siblings ...)
  2012-11-01 16:39                                         ` [U-Boot] [PATCH v3 14/18] env: Add environment variable flags Joe Hershberger
@ 2012-11-01 16:39                                         ` Joe Hershberger
  2012-11-01 16:39                                         ` [U-Boot] [PATCH v3 16/18] env: Add a command to display details about env flags Joe Hershberger
                                                           ` (4 subsequent siblings)
  19 siblings, 0 replies; 124+ messages in thread
From: Joe Hershberger @ 2012-11-01 16:39 UTC (permalink / raw)
  To: u-boot

Currently just validates variable types as decimal, hexidecimal,
boolean, ip address, and mac address.  Call
env_acl_validate_setenv_params() from setenv() in fw_env.c.

If the entry is not found in the env .flags, then look in the static
one. This allows the env to override the static definitions, but prevents
the need to have every definition in the environment distracting you.

Need to build in _ctype for isdigit for Linux.

Signed-off-by: Joe Hershberger <joe.hershberger@ni.com>
---

 common/env_attr.c   |  7 +++++
 common/env_flags.c  | 75 +++++++++++++++++++++++++++++++++++++++++++++++++++++
 include/env_flags.h | 19 ++++++++++++++
 tools/env/Makefile  |  3 +++
 tools/env/fw_env.c  |  9 +++++++
 5 files changed, 113 insertions(+)

diff --git a/common/env_attr.c b/common/env_attr.c
index 7d330a5..210c98d 100644
--- a/common/env_attr.c
+++ b/common/env_attr.c
@@ -21,7 +21,14 @@
  * MA 02111-1307 USA
  */
 
+#ifdef USE_HOSTCC /* Eliminate "ANSI does not permit..." warnings */
+#include <stdint.h>
+#include <stdio.h>
+#include <linux/linux_string.h>
+#else
 #include <common.h>
+#endif
+
 #include <env_attr.h>
 #include <errno.h>
 #include <linux/string.h>
diff --git a/common/env_flags.c b/common/env_flags.c
index 2292569..6ea995a 100644
--- a/common/env_flags.c
+++ b/common/env_flags.c
@@ -24,8 +24,17 @@
 #include <linux/string.h>
 #include <linux/ctype.h>
 
+#ifdef USE_HOSTCC /* Eliminate "ANSI does not permit..." warnings */
+#include <stdint.h>
+#include <stdio.h>
+#include "fw_env.h"
+#include <env_attr.h>
+#include <env_flags.h>
+#define getenv fw_getenv
+#else
 #include <common.h>
 #include <environment.h>
+#endif
 
 #ifdef CONFIG_CMD_NET
 #define ENV_FLAGS_NET_VARTYPE_REPS "im"
@@ -174,6 +183,70 @@ static inline int env_flags_lookup(const char *flags_list, const char *name,
 	return ret;
 }
 
+#ifdef USE_HOSTCC /* Functions only used from tools/env */
+/*
+ * Look up any flags directly from the .flags variable and the static list
+ * and convert them to the vartype enum.
+ */
+enum env_flags_vartype env_flags_get_type(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_vartype_string;
+
+	if (strlen(flags) <= ENV_FLAGS_VARTYPE_LOC)
+		return env_flags_vartype_string;
+
+	return env_flags_parse_vartype(flags);
+}
+
+/*
+ * Validate that the proposed new value for "name" is valid according to the
+ * defined flags for that variable, if any.
+ */
+int env_flags_validate_type(const char *name, const char *value)
+{
+	enum env_flags_vartype type;
+
+	if (value == NULL)
+		return 0;
+	type = env_flags_get_type(name);
+	if (_env_flags_validate_type(value, type) < 0) {
+		printf("## Error: flags type check failure for "
+			"\"%s\" <= \"%s\" (type: %c)\n",
+			name, value, env_flags_vartype_rep[type]);
+		return -1;
+	}
+	return 0;
+}
+
+/*
+ * Validate the parameters to "env set" directly
+ */
+int env_flags_validate_env_set_params(int argc, char * const argv[])
+{
+	if ((argc >= 3) && argv[2] != NULL) {
+		enum env_flags_vartype type = env_flags_get_type(argv[1]);
+
+		/*
+		 * we don't currently check types that need more than
+		 * one argument
+		 */
+		if (type != env_flags_vartype_string && argc > 3) {
+			printf("## Error: too many parameters for setting "
+				"\"%s\"\n", argv[1]);
+			return -1;
+		}
+		return env_flags_validate_type(argv[1], argv[2]);
+	}
+	/* ok */
+	return 0;
+}
+
+#else /* !USE_HOSTCC - Functions only used from lib/hashtable.c */
+
 /*
  * Parse the flag charachters from the .flags attribute list into the binary
  * form to be stored in the environment entry->flags field.
@@ -312,3 +385,5 @@ int env_flags_validate(const ENTRY *item, const char *newval, enum env_op op,
 
 	return 0;
 }
+
+#endif
diff --git a/include/env_flags.h b/include/env_flags.h
index bf25f27..3333446 100644
--- a/include/env_flags.h
+++ b/include/env_flags.h
@@ -52,6 +52,23 @@ enum env_flags_vartype {
  */
 enum env_flags_vartype env_flags_parse_vartype(const char *flags);
 
+#ifdef USE_HOSTCC
+/*
+ * Look up the type of a variable directly from the .flags var.
+ */
+enum env_flags_vartype env_flags_get_type(const char *name);
+/*
+ * Validate the newval for its type to conform with the requirements defined by
+ * its flags (directly looked at the .flags var).
+ */
+int env_flags_validate_type(const char *name, const char *newval);
+/*
+ * Validate the parameters passed to "env set" for type compliance
+ */
+int env_flags_validate_env_set_params(int argc, char * const argv[]);
+
+#else /* !USE_HOSTCC */
+
 #include <search.h>
 
 /*
@@ -73,4 +90,6 @@ int env_flags_validate(const ENTRY *item, const char *newval, enum env_op op,
 #define ENV_FLAGS_VARTYPE_BIN_MASK	0x00000007
 /* The actual variable type values use the enum value (within the mask) */
 
+#endif /* USE_HOSTCC */
+
 #endif /* __ENV_FLAGS_H__ */
diff --git a/tools/env/Makefile b/tools/env/Makefile
index ab73c8c..0e798e0 100644
--- a/tools/env/Makefile
+++ b/tools/env/Makefile
@@ -24,12 +24,15 @@
 include $(TOPDIR)/config.mk
 
 HOSTSRCS := $(SRCTREE)/lib/crc32.c  fw_env.c  fw_env_main.c
+HOSTSRCS += $(SRCTREE)/lib/ctype.c $(SRCTREE)/lib/linux_string.c
+HOSTSRCS += $(SRCTREE)/common/env_attr.c $(SRCTREE)/common/env_flags.c
 HEADERS	:= fw_env.h $(OBJTREE)/include/config.h
 
 # Compile for a hosted environment on the target
 HOSTCPPFLAGS  = -idirafter $(SRCTREE)/include \
 		-idirafter $(OBJTREE)/include2 \
 		-idirafter $(OBJTREE)/include \
+		-idirafter $(SRCTREE)/tools/env \
 		-DUSE_HOSTCC \
 		-DTEXT_BASE=$(TEXT_BASE)
 
diff --git a/tools/env/fw_env.c b/tools/env/fw_env.c
index 9b023e8..5be36fc 100644
--- a/tools/env/fw_env.c
+++ b/tools/env/fw_env.c
@@ -25,6 +25,7 @@
  */
 
 #include <errno.h>
+#include <env_flags.h>
 #include <fcntl.h>
 #include <linux/stringify.h>
 #include <stdio.h>
@@ -395,6 +396,9 @@ int fw_setenv(int argc, char *argv[])
 
 	name = argv[1];
 
+	if (env_flags_validate_env_set_params(argc, argv) < 0)
+		return 1;
+
 	len = 0;
 	for (i = 2; i < argc; ++i) {
 		char *val = argv[i];
@@ -516,6 +520,11 @@ int fw_parse_script(char *fname)
 			name, val ? val : " removed");
 #endif
 
+		if (env_flags_validate_type(name, val) < 0) {
+			ret = -1;
+			break;
+		}
+
 		/*
 		 * If there is an error setting a variable,
 		 * try to save the environment and returns an error
-- 
1.7.11.5

^ permalink raw reply related	[flat|nested] 124+ messages in thread

* [U-Boot] [PATCH v3 16/18] env: Add a command to display details about env flags
  2012-11-01 16:39                                       ` [U-Boot] [PATCH v3 0/18] Add environment call-back and flags capability Joe Hershberger
                                                           ` (14 preceding siblings ...)
  2012-11-01 16:39                                         ` [U-Boot] [PATCH v3 15/18] tools/env: Add environment variable flags support Joe Hershberger
@ 2012-11-01 16:39                                         ` Joe Hershberger
  2012-11-01 16:39                                         ` [U-Boot] [PATCH v3 17/18] env: Add support for access control to .flags Joe Hershberger
                                                           ` (3 subsequent siblings)
  19 siblings, 0 replies; 124+ messages in thread
From: Joe Hershberger @ 2012-11-01 16:39 UTC (permalink / raw)
  To: u-boot

Similar to the env callback command, this will show details about the
options available, the static list, and the currently active variables.

Signed-off-by: Joe Hershberger <joe.hershberger@ni.com>
---

 README              |  1 +
 common/cmd_nvedit.c | 56 +++++++++++++++++++++++++++++++++++++++++++++++++++++
 common/env_flags.c  | 34 ++++++++++++++++++++++++++++++++
 include/env_flags.h | 11 +++++++++++
 4 files changed, 102 insertions(+)

diff --git a/README b/README
index 315ed36..58ac4e7 100644
--- a/README
+++ b/README
@@ -807,6 +807,7 @@ The following options need to be configured:
 		CONFIG_CMD_EEPROM	* EEPROM read/write support
 		CONFIG_CMD_ELF		* bootelf, bootvx
 		CONFIG_CMD_ENV_CALLBACK	* display details about env callbacks
+		CONFIG_CMD_ENV_FLAGS	* display details about env flags
 		CONFIG_CMD_EXPORTENV	* export the environment
 		CONFIG_CMD_EXT2		* ext2 command support
 		CONFIG_CMD_EXT4		* ext4 command support
diff --git a/common/cmd_nvedit.c b/common/cmd_nvedit.c
index cadf0df..4d2e86d 100644
--- a/common/cmd_nvedit.c
+++ b/common/cmd_nvedit.c
@@ -438,6 +438,59 @@ int do_env_callback(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
 }
 #endif
 
+#if defined(CONFIG_CMD_ENV_FLAGS)
+static int print_static_flags(const char *var_name, const char *flags)
+{
+	enum env_flags_vartype type = env_flags_parse_vartype(flags);
+
+	printf("\t%-20s %-20s\n", var_name, env_flags_get_vartype_name(type));
+
+	return 0;
+}
+
+static int print_active_flags(ENTRY *entry)
+{
+	enum env_flags_vartype type;
+
+	if (entry->flags == 0)
+		return 0;
+
+	type = (enum env_flags_vartype)
+		(entry->flags & ENV_FLAGS_VARTYPE_BIN_MASK);
+	printf("\t%-20s %-20s\n", entry->key, env_flags_get_vartype_name(type));
+
+	return 0;
+}
+
+/*
+ * Print the flags available and what variables have flags
+ */
+int do_env_flags(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
+{
+	/* Print the available variable types */
+	printf("Available variable type flags (position %d):\n",
+		ENV_FLAGS_VARTYPE_LOC);
+	puts("\tFlag\tVariable Type Name\n");
+	puts("\t----\t------------------\n");
+	env_flags_print_vartypes();
+	puts("\n");
+
+	/* Print the static flags that may exist */
+	puts("Static flags:\n");
+	printf("\t%-20s %-20s\n", "Variable Name", "Variable Type");
+	printf("\t%-20s %-20s\n", "-------------", "-------------");
+	env_attr_walk(ENV_FLAGS_LIST_STATIC, print_static_flags);
+	puts("\n");
+
+	/* walk through each variable and print the flags if non-default */
+	puts("Active flags:\n");
+	printf("\t%-20s %-20s\n", "Variable Name", "Variable Type");
+	printf("\t%-20s %-20s\n", "-------------", "-------------");
+	hwalk_r(&env_htab, print_active_flags);
+	return 0;
+}
+#endif
+
 /*
  * Interactively edit an environment variable
  */
@@ -906,6 +959,9 @@ static cmd_tbl_t cmd_env_sub[] = {
 #if defined(CONFIG_CMD_ENV_CALLBACK)
 	U_BOOT_CMD_MKENT(callback, 1, 0, do_env_callback, "", ""),
 #endif
+#if defined(CONFIG_CMD_ENV_FLAGS)
+	U_BOOT_CMD_MKENT(flags, 1, 0, do_env_flags, "", ""),
+#endif
 #if defined(CONFIG_CMD_EXPORTENV)
 	U_BOOT_CMD_MKENT(export, 4, 0, do_env_export, "", ""),
 #endif
diff --git a/common/env_flags.c b/common/env_flags.c
index 6ea995a..7afc423 100644
--- a/common/env_flags.c
+++ b/common/env_flags.c
@@ -43,6 +43,40 @@
 #endif
 
 static const char env_flags_vartype_rep[] = "sdxb" ENV_FLAGS_NET_VARTYPE_REPS;
+#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
+};
+
+/*
+ * 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++;
+	}
+}
+
+/*
+ * Return the name of the type.
+ */
+const char *env_flags_get_vartype_name(enum env_flags_vartype type)
+{
+	return env_flags_vartype_names[type];
+}
+#endif /* CONFIG_CMD_ENV_FLAGS */
 
 /*
  * Parse the flags string from a .flags attribute list into the vartype enum.
diff --git a/include/env_flags.h b/include/env_flags.h
index 3333446..7e72523 100644
--- a/include/env_flags.h
+++ b/include/env_flags.h
@@ -47,6 +47,17 @@ enum env_flags_vartype {
 #define ENV_FLAGS_LIST_STATIC \
 	CONFIG_ENV_FLAGS_LIST_STATIC
 
+#ifdef CONFIG_CMD_ENV_FLAGS
+/*
+ * Print the whole list of available type flags.
+ */
+void env_flags_print_vartypes(void);
+/*
+ * Return the name of the type.
+ */
+const char *env_flags_get_vartype_name(enum env_flags_vartype type);
+#endif
+
 /*
  * Parse the flags string from a .flags attribute list into the vartype enum.
  */
-- 
1.7.11.5

^ permalink raw reply related	[flat|nested] 124+ messages in thread

* [U-Boot] [PATCH v3 17/18] env: Add support for access control to .flags
  2012-11-01 16:39                                       ` [U-Boot] [PATCH v3 0/18] Add environment call-back and flags capability Joe Hershberger
                                                           ` (15 preceding siblings ...)
  2012-11-01 16:39                                         ` [U-Boot] [PATCH v3 16/18] env: Add a command to display details about env flags Joe Hershberger
@ 2012-11-01 16:39                                         ` Joe Hershberger
  2012-11-01 16:39                                         ` [U-Boot] [PATCH v3 18/18] env: Handle write-once ethaddr and serial# generically Joe Hershberger
                                                           ` (2 subsequent siblings)
  19 siblings, 0 replies; 124+ messages in thread
From: Joe Hershberger @ 2012-11-01 16:39 UTC (permalink / raw)
  To: u-boot

Add support for read-only, write-once, and change-default.

Signed-off-by: Joe Hershberger <joe.hershberger@ni.com>
---

 README                |  13 ++++-
 common/cmd_nvedit.c   |  31 ++++++++--
 common/env_common.c   |  18 ++++++
 common/env_flags.c    | 153 ++++++++++++++++++++++++++++++++++++++++++++++++--
 include/env_flags.h   |  50 ++++++++++++++++-
 include/environment.h |   3 +
 tools/env/fw_env.c    |  74 ++++++++++++++++++++++--
 7 files changed, 324 insertions(+), 18 deletions(-)

diff --git a/README b/README
index 58ac4e7..ed3f57d 100644
--- a/README
+++ b/README
@@ -3022,7 +3022,8 @@ Configuration Settings:
 
 	The format of the list is:
 		type_attribute = [s|d|x|b|i|m]
-		attributes = type_attribute
+		access_atribute = [a|r|o|c]
+		attributes = type_attribute[access_atribute]
 		entry = variable_name[:attributes]
 		list = entry[,list]
 
@@ -3034,6 +3035,12 @@ Configuration Settings:
 		i - IP address
 		m - MAC address
 
+	The access attributes are:
+		a - Any (default)
+		r - Read-only
+		o - Write-once
+		c - Change-default
+
 	- CONFIG_ENV_FLAGS_LIST_DEFAULT
 		Define this to a list (string) to define the ".flags"
 		envirnoment variable in the default or embedded environment.
@@ -3045,6 +3052,10 @@ Configuration Settings:
 		list, simply add an entry for the same variable name to the
 		".flags" variable.
 
+- CONFIG_ENV_ACCESS_IGNORE_FORCE
+	If defined, don't allow the -f switch to env set override variable
+	access flags.
+
 The following definitions that deal with the placement and management
 of environment data (variable area); in general, we support the
 following configurations:
diff --git a/common/cmd_nvedit.c b/common/cmd_nvedit.c
index 4d2e86d..4c77ced 100644
--- a/common/cmd_nvedit.c
+++ b/common/cmd_nvedit.c
@@ -442,8 +442,11 @@ int do_env_callback(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
 static int print_static_flags(const char *var_name, const char *flags)
 {
 	enum env_flags_vartype type = env_flags_parse_vartype(flags);
+	enum env_flags_varaccess access = env_flags_parse_varaccess(flags);
 
-	printf("\t%-20s %-20s\n", var_name, env_flags_get_vartype_name(type));
+	printf("\t%-20s %-20s %-20s\n", var_name,
+		env_flags_get_vartype_name(type),
+		env_flags_get_varaccess_name(access));
 
 	return 0;
 }
@@ -451,13 +454,17 @@ static int print_static_flags(const char *var_name, const char *flags)
 static int print_active_flags(ENTRY *entry)
 {
 	enum env_flags_vartype type;
+	enum env_flags_varaccess access;
 
 	if (entry->flags == 0)
 		return 0;
 
 	type = (enum env_flags_vartype)
 		(entry->flags & ENV_FLAGS_VARTYPE_BIN_MASK);
-	printf("\t%-20s %-20s\n", entry->key, env_flags_get_vartype_name(type));
+	access = env_flags_parse_varaccess_from_binflags(entry->flags);
+	printf("\t%-20s %-20s %-20s\n", entry->key,
+		env_flags_get_vartype_name(type),
+		env_flags_get_varaccess_name(access));
 
 	return 0;
 }
@@ -475,17 +482,29 @@ int do_env_flags(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
 	env_flags_print_vartypes();
 	puts("\n");
 
+	/* Print the available variable access types */
+	printf("Available variable access flags (position %d):\n",
+		ENV_FLAGS_VARACCESS_LOC);
+	puts("\tFlag\tVariable Access Name\n");
+	puts("\t----\t--------------------\n");
+	env_flags_print_varaccess();
+	puts("\n");
+
 	/* Print the static flags that may exist */
 	puts("Static flags:\n");
-	printf("\t%-20s %-20s\n", "Variable Name", "Variable Type");
-	printf("\t%-20s %-20s\n", "-------------", "-------------");
+	printf("\t%-20s %-20s %-20s\n", "Variable Name", "Variable Type",
+		"Variable Access");
+	printf("\t%-20s %-20s %-20s\n", "-------------", "-------------",
+		"---------------");
 	env_attr_walk(ENV_FLAGS_LIST_STATIC, print_static_flags);
 	puts("\n");
 
 	/* walk through each variable and print the flags if non-default */
 	puts("Active flags:\n");
-	printf("\t%-20s %-20s\n", "Variable Name", "Variable Type");
-	printf("\t%-20s %-20s\n", "-------------", "-------------");
+	printf("\t%-20s %-20s %-20s\n", "Variable Name", "Variable Type",
+		"Variable Access");
+	printf("\t%-20s %-20s %-20s\n", "-------------", "-------------",
+		"---------------");
 	hwalk_r(&env_htab, print_active_flags);
 	return 0;
 }
diff --git a/common/env_common.c b/common/env_common.c
index b711337..3021efe 100644
--- a/common/env_common.c
+++ b/common/env_common.c
@@ -95,6 +95,24 @@ int getenv_yesno(const char *var)
 		1 : 0;
 }
 
+/*
+ * Look up the variable from the default environment
+ */
+char *getenv_default(const char *name)
+{
+	char *ret_val;
+	unsigned long really_valid = gd->env_valid;
+	unsigned long real_gd_flags = gd->flags;
+
+	/* Pretend that the image is bad. */
+	gd->flags &= ~GD_FLG_ENV_READY;
+	gd->env_valid = 0;
+	ret_val = getenv(name);
+	gd->env_valid = really_valid;
+	gd->flags = real_gd_flags;
+	return ret_val;
+}
+
 void set_default_env(const char *s)
 {
 	int flags = 0;
diff --git a/common/env_flags.c b/common/env_flags.c
index 7afc423..9bf7f2d 100644
--- a/common/env_flags.c
+++ b/common/env_flags.c
@@ -43,6 +43,17 @@
 #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",
@@ -54,6 +65,12 @@ static const char * const env_flags_vartype_names[] = {
 	"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.
@@ -70,12 +87,34 @@ void env_flags_print_vartypes(void)
 }
 
 /*
+ * 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 */
 
 /*
@@ -95,6 +134,40 @@ 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 = 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;
+
+	puts("Warning: Non-standard access flags.\n");
+
+	return env_flags_varaccess_any;
+}
+
 static inline int is_hex_prefix(const char *value)
 {
 	return value[0] == '0' && (value[1] == 'x' || value[1] == 'X');
@@ -237,6 +310,23 @@ enum env_flags_vartype env_flags_get_type(const char *name)
 }
 
 /*
+ * 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.
  */
@@ -257,6 +347,21 @@ int env_flags_validate_type(const char *name, const char *value)
 }
 
 /*
+ * 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
  */
 int env_flags_validate_env_set_params(int argc, char * const argv[])
@@ -287,7 +392,12 @@ 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;
 }
 
 /*
@@ -372,13 +482,10 @@ 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;
 
@@ -417,6 +524,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;
 }
 
diff --git a/include/env_flags.h b/include/env_flags.h
index 7e72523..0bdae07 100644
--- a/include/env_flags.h
+++ b/include/env_flags.h
@@ -36,9 +36,18 @@ enum env_flags_vartype {
 	env_flags_vartype_end
 };
 
+enum env_flags_varaccess {
+	env_flags_varaccess_any,
+	env_flags_varaccess_readonly,
+	env_flags_varaccess_writeonce,
+	env_flags_varaccess_changedefault,
+	env_flags_varaccess_end
+};
+
 #define ENV_FLAGS_VAR ".flags"
 #define ENV_FLAGS_ATTR_MAX_LEN 2
 #define ENV_FLAGS_VARTYPE_LOC 0
+#define ENV_FLAGS_VARACCESS_LOC 1
 
 #ifndef CONFIG_ENV_FLAGS_LIST_STATIC
 #define CONFIG_ENV_FLAGS_LIST_STATIC ""
@@ -53,15 +62,31 @@ enum env_flags_vartype {
  */
 void env_flags_print_vartypes(void);
 /*
+ * Print the whole list of available access flags.
+ */
+void env_flags_print_varaccess(void);
+/*
  * Return the name of the type.
  */
 const char *env_flags_get_vartype_name(enum env_flags_vartype type);
+/*
+ * Return the name of the access.
+ */
+const char *env_flags_get_varaccess_name(enum env_flags_varaccess access);
 #endif
 
 /*
  * Parse the flags string from a .flags attribute list into the vartype enum.
  */
 enum env_flags_vartype env_flags_parse_vartype(const char *flags);
+/*
+ * Parse the flags string from a .flags attribute list into the varaccess enum.
+ */
+enum env_flags_varaccess env_flags_parse_varaccess(const char *flags);
+/*
+ * 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);
 
 #ifdef USE_HOSTCC
 /*
@@ -69,11 +94,25 @@ enum env_flags_vartype env_flags_parse_vartype(const char *flags);
  */
 enum env_flags_vartype env_flags_get_type(const char *name);
 /*
+ * Look up the access of a variable directly from the .flags var.
+ */
+enum env_flags_varaccess env_flags_get_access(const char *name);
+/*
  * Validate the newval for its type to conform with the requirements defined by
  * its flags (directly looked at the .flags var).
  */
 int env_flags_validate_type(const char *name, const char *newval);
 /*
+ * Validate the newval for its access to conform with the requirements defined
+ * by its flags (directly looked at the .flags var).
+ */
+int env_flags_validate_access(const char *name, int check_mask);
+/*
+ * 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);
+/*
  * Validate the parameters passed to "env set" for type compliance
  */
 int env_flags_validate_env_set_params(int argc, char * const argv[]);
@@ -94,13 +133,18 @@ void env_flags_init(ENTRY *var_entry);
 int env_flags_validate(const ENTRY *item, const char *newval, enum env_op op,
 	int flag);
 
+#endif /* USE_HOSTCC */
+
 /*
  * These are the binary flags used in the environment entry->flags variable to
  * decribe properties of veriables in the table
  */
-#define ENV_FLAGS_VARTYPE_BIN_MASK	0x00000007
+#define ENV_FLAGS_VARTYPE_BIN_MASK			0x00000007
 /* The actual variable type values use the enum value (within the mask) */
-
-#endif /* USE_HOSTCC */
+#define ENV_FLAGS_VARACCESS_PREVENT_DELETE		0x00000008
+#define ENV_FLAGS_VARACCESS_PREVENT_CREATE		0x00000010
+#define ENV_FLAGS_VARACCESS_PREVENT_OVERWR		0x00000020
+#define ENV_FLAGS_VARACCESS_PREVENT_NONDEF_OVERWR	0x00000040
+#define ENV_FLAGS_VARACCESS_BIN_MASK			0x00000078
 
 #endif /* __ENV_FLAGS_H__ */
diff --git a/include/environment.h b/include/environment.h
index 00e59ba..e64b43d 100644
--- a/include/environment.h
+++ b/include/environment.h
@@ -181,6 +181,9 @@ unsigned char env_get_char_memory(int index);
 /* Function that updates CRC of the enironment */
 void env_crc_update(void);
 
+/* Look up the variable from the default environment */
+char *getenv_default(const char *name);
+
 /* [re]set to the default environment */
 void set_default_env(const char *s);
 
diff --git a/tools/env/fw_env.c b/tools/env/fw_env.c
index 5be36fc..a596a1b 100644
--- a/tools/env/fw_env.c
+++ b/tools/env/fw_env.c
@@ -182,6 +182,32 @@ char *fw_getenv (char *name)
 }
 
 /*
+ * Search the default environment for a variable.
+ * Return the value, if found, or NULL, if not found.
+ */
+char *fw_getdefenv(char *name)
+{
+	char *env, *nxt;
+
+	for (env = default_environment; *env; env = nxt + 1) {
+		char *val;
+
+		for (nxt = env; *nxt; ++nxt) {
+			if (nxt >= &default_environment[ENV_SIZE]) {
+				fprintf(stderr, "## Error: "
+					"default environment not terminated\n");
+				return NULL;
+			}
+		}
+		val = envmatch(name, env);
+		if (!val)
+			continue;
+		return val;
+	}
+	return NULL;
+}
+
+/*
  * Print the current definition of one, or more, or all
  * environment variables
  */
@@ -282,6 +308,7 @@ int fw_env_write(char *name, char *value)
 	int len;
 	char *env, *nxt;
 	char *oldval = NULL;
+	int deleting, creating, overwriting;
 
 	/*
 	 * search if variable with this name already exists
@@ -299,10 +326,49 @@ int fw_env_write(char *name, char *value)
 			break;
 	}
 
-	/*
-	 * Delete any existing definition
-	 */
-	if (oldval) {
+	deleting = (oldval && !(value && strlen(value)));
+	creating = (!oldval && (value && strlen(value)));
+	overwriting = (oldval && (value && strlen(value)));
+
+	/* check for permission */
+	if (deleting) {
+		if (env_flags_validate_varaccess(name,
+		    ENV_FLAGS_VARACCESS_PREVENT_DELETE)) {
+			printf("Can't delete \"%s\"\n", name);
+			errno = EROFS;
+			return -1;
+		}
+	} else if (overwriting) {
+		if (env_flags_validate_varaccess(name,
+		    ENV_FLAGS_VARACCESS_PREVENT_OVERWR)) {
+			printf("Can't overwrite \"%s\"\n", name);
+			errno = EROFS;
+			return -1;
+		} else if (env_flags_validate_varaccess(name,
+		    ENV_FLAGS_VARACCESS_PREVENT_NONDEF_OVERWR)) {
+			const char *defval = fw_getdefenv(name);
+
+			if (defval == NULL)
+				defval = "";
+			if (strcmp(oldval, defval)
+			    != 0) {
+				printf("Can't overwrite \"%s\"\n", name);
+				errno = EROFS;
+				return -1;
+			}
+		}
+	} else if (creating) {
+		if (env_flags_validate_varaccess(name,
+		    ENV_FLAGS_VARACCESS_PREVENT_CREATE)) {
+			printf("Can't create \"%s\"\n", name);
+			errno = EROFS;
+			return -1;
+		}
+	} else
+		/* Nothing to do */
+		return 0;
+
+	if (deleting || overwriting) {
 #ifndef CONFIG_ENV_OVERWRITE
 		/*
 		 * Ethernet Address and serial# can be set only once
-- 
1.7.11.5

^ permalink raw reply related	[flat|nested] 124+ messages in thread

* [U-Boot] [PATCH v3 18/18] env: Handle write-once ethaddr and serial# generically
  2012-11-01 16:39                                       ` [U-Boot] [PATCH v3 0/18] Add environment call-back and flags capability Joe Hershberger
                                                           ` (16 preceding siblings ...)
  2012-11-01 16:39                                         ` [U-Boot] [PATCH v3 17/18] env: Add support for access control to .flags Joe Hershberger
@ 2012-11-01 16:39                                         ` Joe Hershberger
  2012-11-02 22:40                                         ` [U-Boot] [PATCH v3 0/18] Add environment call-back and flags capability Wolfgang Denk
  2012-12-05  1:52                                         ` [U-Boot] [PATCH v4 0/20] " Joe Hershberger
  19 siblings, 0 replies; 124+ messages in thread
From: Joe Hershberger @ 2012-11-01 16:39 UTC (permalink / raw)
  To: u-boot

Use the variable access flags to implement the protection for ethaddr
and serial# instead of hard-coding them.

Signed-off-by: Joe Hershberger <joe.hershberger@ni.com>
---

 common/env_flags.c  | 19 -------------------
 include/env_flags.h | 22 ++++++++++++++++++++++
 tools/env/fw_env.c  | 17 -----------------
 3 files changed, 22 insertions(+), 36 deletions(-)

diff --git a/common/env_flags.c b/common/env_flags.c
index 9bf7f2d..8d2a12c 100644
--- a/common/env_flags.c
+++ b/common/env_flags.c
@@ -492,25 +492,6 @@ int env_flags_validate(const ENTRY *item, const char *newval, enum env_op op,
 	/* 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;
diff --git a/include/env_flags.h b/include/env_flags.h
index 0bdae07..d1aa144 100644
--- a/include/env_flags.h
+++ b/include/env_flags.h
@@ -53,7 +53,29 @@ enum env_flags_varaccess {
 #define CONFIG_ENV_FLAGS_LIST_STATIC ""
 #endif
 
+#ifdef CONFIG_CMD_NET
+#ifdef CONFIG_ENV_OVERWRITE
+#define ETHADDR_FLAGS "ethaddr:ma,"
+#else
+#ifdef CONFIG_OVERWRITE_ETHADDR_ONCE
+#define ETHADDR_FLAGS "ethaddr:mc,"
+#else
+#define ETHADDR_FLAGS "ethaddr:mo,"
+#endif
+#endif
+#else
+#define ETHADDR_FLAGS ""
+#endif
+
+#ifndef CONFIG_ENV_OVERWRITE
+#define SERIAL_FLAGS "serial#:so,"
+#else
+#define SERIAL_FLAGS ""
+#endif
+
 #define ENV_FLAGS_LIST_STATIC \
+	ETHADDR_FLAGS \
+	SERIAL_FLAGS \
 	CONFIG_ENV_FLAGS_LIST_STATIC
 
 #ifdef CONFIG_CMD_ENV_FLAGS
diff --git a/tools/env/fw_env.c b/tools/env/fw_env.c
index a596a1b..90c7a5d 100644
--- a/tools/env/fw_env.c
+++ b/tools/env/fw_env.c
@@ -369,23 +369,6 @@ int fw_env_write(char *name, char *value)
 		return 0;
 
 	if (deleting || overwriting) {
-#ifndef CONFIG_ENV_OVERWRITE
-		/*
-		 * Ethernet Address and serial# can be set only once
-		 */
-		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 */
-		   ) ) {
-			fprintf (stderr, "Can't overwrite \"%s\"\n", name);
-			errno = EROFS;
-			return -1;
-		}
-#endif /* CONFIG_ENV_OVERWRITE */
-
 		if (*++nxt == '\0') {
 			*env = '\0';
 		} else {
-- 
1.7.11.5

^ permalink raw reply related	[flat|nested] 124+ messages in thread

* [U-Boot] [PATCH v3 06/18] env: Hide '.' variables in env print by default
  2012-11-01 16:39                                         ` [U-Boot] [PATCH v3 06/18] env: Hide '.' variables in env print by default Joe Hershberger
@ 2012-11-02 10:44                                           ` Luka Perkov
  2012-11-02 22:23                                             ` Wolfgang Denk
  0 siblings, 1 reply; 124+ messages in thread
From: Luka Perkov @ 2012-11-02 10:44 UTC (permalink / raw)
  To: u-boot

Hi Joe,

On Thu, Nov 01, 2012 at 11:39:43AM -0500, Joe Hershberger wrote:
> When printing all variables with env print, don't print variables that
> begin with '.'.  If env print is called with a '-a' switch, then
> include variables that begin with '.' (just like the ls command).
> 
> Variables printed explicitly will be printed even without the -a.

Can you tell us use case for this ? Which variables you would like to
"hide" ?

Luka

^ permalink raw reply	[flat|nested] 124+ messages in thread

* [U-Boot] [PATCH v3 06/18] env: Hide '.' variables in env print by default
  2012-11-02 10:44                                           ` Luka Perkov
@ 2012-11-02 22:23                                             ` Wolfgang Denk
  0 siblings, 0 replies; 124+ messages in thread
From: Wolfgang Denk @ 2012-11-02 22:23 UTC (permalink / raw)
  To: u-boot

Dear Luka Perkov,

In message <20121102104454.GA10982@w500> you wrote:
> 
> On Thu, Nov 01, 2012 at 11:39:43AM -0500, Joe Hershberger wrote:
> > When printing all variables with env print, don't print variables that
> > begin with '.'.  If env print is called with a '-a' switch, then
> > include variables that begin with '.' (just like the ls command).
> > 
> > Variables printed explicitly will be printed even without the -a.
> 
> Can you tell us use case for this ? Which variables you would like to
> "hide" ?

For example ".flags" or ".callbacks".

Best regards,

Wolfgang Denk

-- 
DENX Software Engineering GmbH,     MD: Wolfgang Denk & Detlev Zundel
HRB 165235 Munich, Office: Kirchenstr.5, D-82194 Groebenzell, Germany
Phone: (+49)-8142-66989-10 Fax: (+49)-8142-66989-80 Email: wd at denx.de
Of all possible committee reactions to any  given  agenda  item,  the
reaction  that will occur is the one which will liberate the greatest
amount of hot air.                                -- Thomas L. Martin

^ permalink raw reply	[flat|nested] 124+ messages in thread

* [U-Boot] [PATCH v3 0/18] Add environment call-back and flags capability
  2012-11-01 16:39                                       ` [U-Boot] [PATCH v3 0/18] Add environment call-back and flags capability Joe Hershberger
                                                           ` (17 preceding siblings ...)
  2012-11-01 16:39                                         ` [U-Boot] [PATCH v3 18/18] env: Handle write-once ethaddr and serial# generically Joe Hershberger
@ 2012-11-02 22:40                                         ` Wolfgang Denk
  2012-11-05  0:15                                           ` Joe Hershberger
  2012-12-01 19:44                                           ` Joe Hershberger
  2012-12-05  1:52                                         ` [U-Boot] [PATCH v4 0/20] " Joe Hershberger
  19 siblings, 2 replies; 124+ messages in thread
From: Wolfgang Denk @ 2012-11-02 22:40 UTC (permalink / raw)
  To: u-boot

Dear Joe Hershberger,

In message <1351787996-24560-1-git-send-email-joe.hershberger@ni.com> you wrote:
> 
> When a variable with a registered callback is inserted, deleted, or
> overwritten the callback is called and gives the system an opportunity
> to do something in response to the change.  It also has the opportunuty
> to reject the change by returning non-zero.

I applied the patch series against current top of tree and tested on a
PPC board ("sequoia").  It hangs without printing any message.

Guess I need to attach a BDI ...

To which extend have these patches been tested on real hardware, and
on which exact platforms?

Best regards,

Wolfgang Denk

-- 
DENX Software Engineering GmbH,     MD: Wolfgang Denk & Detlev Zundel
HRB 165235 Munich, Office: Kirchenstr.5, D-82194 Groebenzell, Germany
Phone: (+49)-8142-66989-10 Fax: (+49)-8142-66989-80 Email: wd at denx.de
Knowledge, sir, should be free to all!
	-- Harry Mudd, "I, Mudd", stardate 4513.3

^ permalink raw reply	[flat|nested] 124+ messages in thread

* [U-Boot] [PATCH v3 0/18] Add environment call-back and flags capability
  2012-11-02 22:40                                         ` [U-Boot] [PATCH v3 0/18] Add environment call-back and flags capability Wolfgang Denk
@ 2012-11-05  0:15                                           ` Joe Hershberger
  2012-12-01 19:44                                           ` Joe Hershberger
  1 sibling, 0 replies; 124+ messages in thread
From: Joe Hershberger @ 2012-11-05  0:15 UTC (permalink / raw)
  To: u-boot

Hi Wolfgang,

On Fri, Nov 2, 2012 at 5:40 PM, Wolfgang Denk <wd@denx.de> wrote:
> Dear Joe Hershberger,
>
> In message <1351787996-24560-1-git-send-email-joe.hershberger@ni.com> you wrote:
>>
>> When a variable with a registered callback is inserted, deleted, or
>> overwritten the callback is called and gives the system an opportunity
>> to do something in response to the change.  It also has the opportunuty
>> to reject the change by returning non-zero.
>
> I applied the patch series against current top of tree and tested on a
> PPC board ("sequoia").  It hangs without printing any message.

I'll test on MPC8313 this week.  That's the closest thing I have to
the target that is not working for you.

> Guess I need to attach a BDI ...
>
> To which extend have these patches been tested on real hardware, and
> on which exact platforms?

This was tested on omap4_panda pretty thoroughly.

-Joe

^ permalink raw reply	[flat|nested] 124+ messages in thread

* [U-Boot] [PATCH v3 0/18] Add environment call-back and flags capability
  2012-11-02 22:40                                         ` [U-Boot] [PATCH v3 0/18] Add environment call-back and flags capability Wolfgang Denk
  2012-11-05  0:15                                           ` Joe Hershberger
@ 2012-12-01 19:44                                           ` Joe Hershberger
  1 sibling, 0 replies; 124+ messages in thread
From: Joe Hershberger @ 2012-12-01 19:44 UTC (permalink / raw)
  To: u-boot

Hi Wolfgang,

On Fri, Nov 2, 2012 at 5:40 PM, Wolfgang Denk <wd@denx.de> wrote:
> Dear Joe Hershberger,
>
> In message <1351787996-24560-1-git-send-email-joe.hershberger@ni.com> you wrote:
>>
>> When a variable with a registered callback is inserted, deleted, or
>> overwritten the callback is called and gives the system an opportunity
>> to do something in response to the change.  It also has the opportunuty
>> to reject the change by returning non-zero.
>
> I applied the patch series against current top of tree and tested on a
> PPC board ("sequoia").  It hangs without printing any message.

I am seeing a hang on my ARM boards that are using NAND flash for the
env.  The hang seems to be env contents dependent.  I'm still
investigating, but it could be related to the issue you're seeing.
For me it hangs (sometimes, depending on env) after mmc init and
before console init traces anything.

> Guess I need to attach a BDI ...

Did you get around to looking at it with the debugger?

Thanks,
-Joe

^ permalink raw reply	[flat|nested] 124+ messages in thread

* [U-Boot] [PATCH v4 0/20] Add environment call-back and flags capability
  2012-11-01 16:39                                       ` [U-Boot] [PATCH v3 0/18] Add environment call-back and flags capability Joe Hershberger
                                                           ` (18 preceding siblings ...)
  2012-11-02 22:40                                         ` [U-Boot] [PATCH v3 0/18] Add environment call-back and flags capability Wolfgang Denk
@ 2012-12-05  1:52                                         ` Joe Hershberger
  2012-12-05  1:52                                           ` [U-Boot] [PATCH v4 01/20] Make linux kernel string funcs available to tools Joe Hershberger
                                                             ` (21 more replies)
  19 siblings, 22 replies; 124+ messages in thread
From: Joe Hershberger @ 2012-12-05  1:52 UTC (permalink / raw)
  To: u-boot


When a variable with a registered callback is inserted, deleted, or
overwritten the callback is called and gives the system an opportunity
to do something in response to the change.  It also has the opportunuty
to reject the change by returning non-zero.

The flags on variables can control their type as well as their allowed
access.

        The format of the list is:
                type_attribute = [s|d|x|b|i|m]
                attributes = type_attribute
                entry = variable_name[:attributes]
                list = entry[,list]

        The type attributes are:
                s - String (default)
                d - Decimal
                x - Hexadecimal
                b - Boolean ([1yYtT|0nNfF])
                i - IP address
                m - MAC address

        The access attributes are:
                a - Any (default)
                r - Read-only
                o - Write-once
                c - Change-default

Changes in v4:
- Prevent crash on relocation import
- Fixed help text
- Add help text for env flags command
- Add force support to setenv
- Implement delete

Changes in v3:
- Rebase onto Gerlando Falauto's env patches
- Refactor himport_r() and hsearch_r()'s parameters
- Split hdelete_r() into the core delete and the validation before
delete
- Delete vars on failed insertion
- Use Marek's linker lists instead of implementing it directly
- Rebase onto latest master
- Add flags parameter to callbacks
- Implement reverse search in env_attr_lookup()
- Fix space skipping in env_attr_lookup()
- All errors coming back from hsearch_r() are no longer fatal.  Don't
abort import on failed ENTER action.
- Removed checkpatch.pl warning

Changes in v2:
- Added much-needed documentation
- Factored out prevch and nextch in env_attr_lookup()

Joe Hershberger (20):
  Make linux kernel string funcs available to tools
  env: Refactor do_apply to a flag
  env: Consolidate common code in hsearch_r()
  env: Refactor apply into change_ok
  env: Use getenv_yesno() more generally
  env: Hide '.' variables in env print by default
  env: Add support for callbacks to environment vars
  env: Add a command to view callbacks
  env: Add a bootfile env handler
  env: Add a baudrate env handler
  env: Add a loadaddr env handler
  env: Add a console env handler
  env: Add a silent env handler
  env: Add environment variable flags
  tools/env: Add environment variable flags support
  env: Add a command to display details about env flags
  env: Add support for access control to .flags
  env: Add setenv force support
  env: Implement the env delete command
  env: Handle write-once ethaddr and serial# generically

 README                          |  80 ++++++
 arch/arm/lib/board.c            |   4 +-
 arch/m68k/lib/board.c           |   3 +-
 arch/microblaze/lib/board.c     |   4 +-
 arch/powerpc/cpu/mpc85xx/mp.c   |   4 +-
 arch/powerpc/lib/board.c        |   9 +-
 arch/sparc/lib/board.c          |   3 +-
 board/Marvell/db64360/db64360.c |  10 +-
 board/Marvell/db64460/db64460.c |  10 +-
 board/esd/cpci750/cpci750.c     |  10 +-
 board/esd/pmc440/cmd_pmc440.c   |   2 +-
 board/gw8260/gw8260.c           |  10 +-
 board/prodrive/p3mx/p3mx.c      |  10 +-
 common/Makefile                 |   6 +
 common/cmd_nvedit.c             | 402 ++++++++++++++++-------------
 common/console.c                |  75 +++++-
 common/env_attr.c               | 229 +++++++++++++++++
 common/env_callback.c           | 132 ++++++++++
 common/env_common.c             |  60 +++--
 common/env_dataflash.c          |   2 +-
 common/env_eeprom.c             |   2 +-
 common/env_fat.c                |   2 +-
 common/env_flags.c              | 549 ++++++++++++++++++++++++++++++++++++++++
 common/env_flash.c              |   4 +-
 common/env_mmc.c                |   2 +-
 common/env_nand.c               |   4 +-
 common/env_nvram.c              |   2 +-
 common/env_onenand.c            |   2 +-
 common/env_sf.c                 |   4 +-
 common/image.c                  |  21 +-
 doc/README.silent               |  14 +-
 drivers/serial/serial.c         |  70 +++++
 include/common.h                |   5 +
 include/env_attr.h              |  55 ++++
 include/env_callback.h          |  75 ++++++
 include/env_default.h           |   8 +
 include/env_flags.h             | 172 +++++++++++++
 include/environment.h           |  15 +-
 include/image.h                 |   1 -
 include/linux/linux_string.h    |   8 +
 include/linux/string.h          |   5 +-
 include/search.h                |  37 ++-
 lib/Makefile                    |   1 +
 lib/hashtable.c                 | 244 ++++++++++++------
 lib/linux_string.c              |  51 ++++
 lib/string.c                    |  39 ---
 net/net.c                       |  49 ++--
 tools/env/Makefile              |   3 +
 tools/env/fw_env.c              |  92 +++++--
 49 files changed, 2154 insertions(+), 447 deletions(-)
 create mode 100644 common/env_attr.c
 create mode 100644 common/env_callback.c
 create mode 100644 common/env_flags.c
 create mode 100644 include/env_attr.h
 create mode 100644 include/env_callback.h
 create mode 100644 include/env_flags.h
 create mode 100644 include/linux/linux_string.h
 create mode 100644 lib/linux_string.c

-- 
1.7.11.5

^ permalink raw reply	[flat|nested] 124+ messages in thread

* [U-Boot] [PATCH v4 01/20] Make linux kernel string funcs available to tools
  2012-12-05  1:52                                         ` [U-Boot] [PATCH v4 0/20] " Joe Hershberger
@ 2012-12-05  1:52                                           ` Joe Hershberger
  2012-12-05  1:52                                           ` [U-Boot] [PATCH v4 02/20] env: Refactor do_apply to a flag Joe Hershberger
                                                             ` (20 subsequent siblings)
  21 siblings, 0 replies; 124+ messages in thread
From: Joe Hershberger @ 2012-12-05  1:52 UTC (permalink / raw)
  To: u-boot

isspace() and strim() are not in the typical user-mode string.h, so
put them in a separate compilation unit so that they can be built into
tools that need them independent of the other common string functions.

This allows code shared by u-boot and the linux user-mode tools to link.

Signed-off-by: Joe Hershberger <joe.hershberger@ni.com>
---
Changes in v4: None
Changes in v3: None
Changes in v2: None

 include/linux/linux_string.h |  8 +++++++
 include/linux/string.h       |  5 +----
 lib/Makefile                 |  1 +
 lib/linux_string.c           | 51 ++++++++++++++++++++++++++++++++++++++++++++
 lib/string.c                 | 39 ---------------------------------
 5 files changed, 61 insertions(+), 43 deletions(-)
 create mode 100644 include/linux/linux_string.h
 create mode 100644 lib/linux_string.c

diff --git a/include/linux/linux_string.h b/include/linux/linux_string.h
new file mode 100644
index 0000000..192b4c9
--- /dev/null
+++ b/include/linux/linux_string.h
@@ -0,0 +1,8 @@
+#ifndef _LINUX_LINUX_STRING_H_
+#define _LINUX_LINUX_STRING_H_
+
+extern char * skip_spaces(const char *);
+
+extern char *strim(char *);
+
+#endif
diff --git a/include/linux/string.h b/include/linux/string.h
index 9a8cbc2..2a6e52f 100644
--- a/include/linux/string.h
+++ b/include/linux/string.h
@@ -47,10 +47,7 @@ extern char * strchr(const char *,int);
 #ifndef __HAVE_ARCH_STRRCHR
 extern char * strrchr(const char *,int);
 #endif
-extern char * skip_spaces(const char *);
-
-extern char *strim(char *);
-
+#include <linux/linux_string.h>
 #ifndef __HAVE_ARCH_STRSTR
 extern char * strstr(const char *,const char *);
 #endif
diff --git a/lib/Makefile b/lib/Makefile
index e44e045..5652986 100644
--- a/lib/Makefile
+++ b/lib/Makefile
@@ -68,6 +68,7 @@ endif
 COBJS-y += crc32.o
 COBJS-y += ctype.o
 COBJS-y += div64.o
+COBJS-y += linux_string.o
 COBJS-y += string.o
 COBJS-y += time.o
 COBJS-$(CONFIG_BOOTP_PXE) += uuid.o
diff --git a/lib/linux_string.c b/lib/linux_string.c
new file mode 100644
index 0000000..d5a5e08
--- /dev/null
+++ b/lib/linux_string.c
@@ -0,0 +1,51 @@
+/*
+ *  linux/lib/string.c
+ *
+ *  Copyright (C) 1991, 1992  Linus Torvalds
+ */
+
+#ifdef USE_HOSTCC
+#include <stdio.h>
+#endif
+
+#include <linux/ctype.h>
+#include <linux/string.h>
+
+/**
+ * skip_spaces - Removes leading whitespace from @str.
+ * @str: The string to be stripped.
+ *
+ * Returns a pointer to the first non-whitespace character in @str.
+ */
+char *skip_spaces(const char *str)
+{
+	while (isspace(*str))
+		++str;
+	return (char *)str;
+}
+
+/**
+ * strim - Removes leading and trailing whitespace from @s.
+ * @s: The string to be stripped.
+ *
+ * Note that the first trailing whitespace is replaced with a %NUL-terminator
+ * in the given string @s. Returns a pointer to the first non-whitespace
+ * character in @s.
+ */
+char *strim(char *s)
+{
+	size_t size;
+	char *end;
+
+	s = skip_spaces(s);
+	size = strlen(s);
+	if (!size)
+		return s;
+
+	end = s + size - 1;
+	while (end >= s && isspace(*end))
+		end--;
+	*(end + 1) = '\0';
+
+	return s;
+}
diff --git a/lib/string.c b/lib/string.c
index c3ad055..2c4f0ec 100644
--- a/lib/string.c
+++ b/lib/string.c
@@ -214,45 +214,6 @@ char * strrchr(const char * s, int c)
 }
 #endif
 
-
-/**
- * skip_spaces - Removes leading whitespace from @str.
- * @str: The string to be stripped.
- *
- * Returns a pointer to the first non-whitespace character in @str.
- */
-char *skip_spaces(const char *str)
-{
-	while (isspace(*str))
-		++str;
-	return (char *)str;
-}
-
-/**
- * strim - Removes leading and trailing whitespace from @s.
- * @s: The string to be stripped.
- *
- * Note that the first trailing whitespace is replaced with a %NUL-terminator
- * in the given string @s. Returns a pointer to the first non-whitespace
- * character in @s.
- */
-char *strim(char *s)
-{
-	size_t size;
-	char *end;
-
-	s = skip_spaces(s);
-	size = strlen(s);
-	if (!size)
-		return s;
-
-	end = s + size - 1;
-	while (end >= s && isspace(*end))
-		end--;
-	*(end + 1) = '\0';
-
-	return s;
-}
 #ifndef __HAVE_ARCH_STRLEN
 /**
  * strlen - Find the length of a string
-- 
1.7.11.5

^ permalink raw reply related	[flat|nested] 124+ messages in thread

* [U-Boot] [PATCH v4 02/20] env: Refactor do_apply to a flag
  2012-12-05  1:52                                         ` [U-Boot] [PATCH v4 0/20] " Joe Hershberger
  2012-12-05  1:52                                           ` [U-Boot] [PATCH v4 01/20] Make linux kernel string funcs available to tools Joe Hershberger
@ 2012-12-05  1:52                                           ` Joe Hershberger
  2012-12-05  1:52                                           ` [U-Boot] [PATCH v4 03/20] env: Consolidate common code in hsearch_r() Joe Hershberger
                                                             ` (19 subsequent siblings)
  21 siblings, 0 replies; 124+ messages in thread
From: Joe Hershberger @ 2012-12-05  1:52 UTC (permalink / raw)
  To: u-boot

Use a flag in hsearch_r for insert mode passed from import to allow the
behavior be different based on use.

Now that "do_check" is called for all imports, ensure console init is
complete before updating the console on relocation import

Signed-off-by: Joe Hershberger <joe.hershberger@ni.com>
---
Changes in v4:
- Prevent crash on relocation import

Changes in v3:
- Rebase onto Gerlando Falauto's env patches
- Refactor himport_r() and hsearch_r()'s parameters

Changes in v2: None

 common/cmd_nvedit.c | 19 +++++++++----------
 common/console.c    |  8 ++++----
 common/env_common.c | 26 ++++++++------------------
 include/search.h    | 15 ++++++++-------
 lib/hashtable.c     | 37 ++++++++++++++++++++-----------------
 5 files changed, 49 insertions(+), 56 deletions(-)

diff --git a/common/cmd_nvedit.c b/common/cmd_nvedit.c
index 006131f..a8dc9a6 100644
--- a/common/cmd_nvedit.c
+++ b/common/cmd_nvedit.c
@@ -116,7 +116,7 @@ static int env_print(char *name)
 
 		e.key = name;
 		e.data = NULL;
-		hsearch_r(e, FIND, &ep, &env_htab);
+		hsearch_r(e, FIND, &ep, &env_htab, 0);
 		if (ep == NULL)
 			return 0;
 		len = printf("%s=%s\n", ep->key, ep->data);
@@ -224,7 +224,7 @@ int env_check_apply(const char *name, const char *oldval,
 	else if (strcmp(name, "stderr") == 0)
 		console = stderr;
 
-	if (console != -1) {
+	if (console != -1 && (gd->flags & GD_FLG_DEVINIT) != 0) {
 		if ((newval == NULL) || (*newval == '\0')) {
 			/* We cannot delete stdin/stdout/stderr */
 			if ((flag & H_FORCE) == 0)
@@ -344,20 +344,19 @@ static int _do_env_set(int flag, int argc, char * const argv[])
 	 */
 	e.key = name;
 	e.data = NULL;
-	hsearch_r(e, FIND, &ep, &env_htab);
+	hsearch_r(e, FIND, &ep, &env_htab, 0);
 
 	/*
-	 * Perform requested checks. Notice how since we are overwriting
-	 * a single variable, we need to set H_NOCLEAR
+	 * Perform requested checks.
 	 */
-	if (env_check_apply(name, ep ? ep->data : NULL, value, H_NOCLEAR)) {
+	if (env_check_apply(name, ep ? ep->data : NULL, value, 0)) {
 		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, 0);
+		int rc = hdelete_r(name, &env_htab, H_INTERACTIVE);
 		return !rc;
 	}
 
@@ -384,7 +383,7 @@ static int _do_env_set(int flag, int argc, char * const argv[])
 
 	e.key	= name;
 	e.data	= value;
-	hsearch_r(e, ENTER, &ep, &env_htab);
+	hsearch_r(e, ENTER, &ep, &env_htab, H_INTERACTIVE);
 	free(value);
 	if (!ep) {
 		printf("## Error inserting \"%s\" variable, errno=%d\n",
@@ -552,7 +551,7 @@ char *getenv(const char *name)
 
 		e.key	= name;
 		e.data	= NULL;
-		hsearch_r(e, FIND, &ep, &env_htab);
+		hsearch_r(e, FIND, &ep, &env_htab, 0);
 
 		return ep ? ep->data : NULL;
 	}
@@ -951,7 +950,7 @@ static int do_env_import(cmd_tbl_t *cmdtp, int flag,
 	}
 
 	if (himport_r(&env_htab, addr, size, sep, del ? 0 : H_NOCLEAR,
-			0, NULL, 0 /* do_apply */) == 0) {
+			0, NULL) == 0) {
 		error("Environment import failed: errno = %d\n", errno);
 		return 1;
 	}
diff --git a/common/console.c b/common/console.c
index 1177f7d..880acd9 100644
--- a/common/console.c
+++ b/common/console.c
@@ -683,8 +683,6 @@ int console_init_r(void)
 done:
 #endif
 
-	gd->flags |= GD_FLG_DEVINIT;	/* device initialization completed */
-
 	stdio_print_current_devices();
 
 #ifdef CONFIG_SYS_CONSOLE_ENV_OVERWRITE
@@ -694,6 +692,8 @@ done:
 	}
 #endif /* CONFIG_SYS_CONSOLE_ENV_OVERWRITE */
 
+	gd->flags |= GD_FLG_DEVINIT;	/* device initialization completed */
+
 #if 0
 	/* If nothing usable installed, use only the initial console */
 	if ((stdio_devices[stdin] == NULL) && (stdio_devices[stdout] == NULL))
@@ -758,8 +758,6 @@ int console_init_r(void)
 #endif
 	}
 
-	gd->flags |= GD_FLG_DEVINIT;	/* device initialization completed */
-
 	stdio_print_current_devices();
 
 	/* Setting environment variables */
@@ -767,6 +765,8 @@ int console_init_r(void)
 		setenv(stdio_names[i], stdio_devices[i]->name);
 	}
 
+	gd->flags |= GD_FLG_DEVINIT;	/* device initialization completed */
+
 #if 0
 	/* If nothing usable installed, use only the initial console */
 	if ((stdio_devices[stdin] == NULL) && (stdio_devices[stdout] == NULL))
diff --git a/common/env_common.c b/common/env_common.c
index 3d3cb70..f22f5b9 100644
--- a/common/env_common.c
+++ b/common/env_common.c
@@ -83,11 +83,8 @@ 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
-	 */
-	int do_apply = 0;
+	int flags = 0;
+
 	if (sizeof(default_environment) > ENV_SIZE) {
 		puts("*** Error - default environment is too large\n\n");
 		return;
@@ -99,14 +96,7 @@ 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 check every single
-			 * variable and apply changes to the system
-			 * right away (e.g. baudrate, console).
-			 */
-			do_apply = 1;
+			flags = H_INTERACTIVE;
 			puts(s);
 		}
 	} else {
@@ -114,8 +104,8 @@ void set_default_env(const char *s)
 	}
 
 	if (himport_r(&env_htab, (char *)default_environment,
-			sizeof(default_environment), '\0', 0,
-			0, NULL, do_apply) == 0)
+			sizeof(default_environment), '\0', flags,
+			0, NULL) == 0)
 		error("Environment import failed: errno = %d\n", errno);
 
 	gd->flags |= GD_FLG_ENV_READY;
@@ -130,8 +120,8 @@ int set_default_vars(int nvars, char * const vars[])
 	 * (and use \0 as a separator)
 	 */
 	return himport_r(&env_htab, (const char *)default_environment,
-				sizeof(default_environment), '\0', H_NOCLEAR,
-				nvars, vars, 1 /* do_apply */);
+				sizeof(default_environment), '\0',
+				H_NOCLEAR | H_INTERACTIVE, nvars, vars);
 }
 
 #ifndef CONFIG_SPL_BUILD
@@ -155,7 +145,7 @@ int env_import(const char *buf, int check)
 	}
 
 	if (himport_r(&env_htab, (char *)ep->data, ENV_SIZE, '\0', 0,
-			0, NULL, 0 /* do_apply */)) {
+			0, NULL)) {
 		gd->flags |= GD_FLG_ENV_READY;
 		return 1;
 	}
diff --git a/include/search.h b/include/search.h
index 93e1cbc..f5165b0 100644
--- a/include/search.h
+++ b/include/search.h
@@ -73,7 +73,7 @@ struct hsearch_data {
 extern int hcreate_r(size_t __nel, struct hsearch_data *__htab);
 
 /* Destroy current internal hashing table.  */
-extern void hdestroy_r(struct hsearch_data *__htab, int do_apply);
+extern void hdestroy_r(struct hsearch_data *__htab);
 
 /*
  * Search for entry matching ITEM.key in internal hash table.  If
@@ -82,7 +82,7 @@ extern void hdestroy_r(struct hsearch_data *__htab, int do_apply);
  * ITEM.data.
  * */
 extern int hsearch_r(ENTRY __item, ACTION __action, ENTRY ** __retval,
-		     struct hsearch_data *__htab);
+		     struct hsearch_data *__htab, int __flag);
 
 /*
  * Search for an entry matching `MATCH'.  Otherwise, Same semantics
@@ -99,7 +99,7 @@ extern int hstrstr_r(const char *__match, int __last_idx, ENTRY ** __retval,
 
 /* Search and delete entry matching ITEM.key in internal hash table. */
 extern int hdelete_r(const char *__key, struct hsearch_data *__htab,
-			int do_apply);
+		     int __flag);
 
 extern ssize_t hexport_r(struct hsearch_data *__htab,
 		     const char __sep, char **__resp, size_t __size,
@@ -113,10 +113,11 @@ extern ssize_t hexport_r(struct hsearch_data *__htab,
  */
 extern int himport_r(struct hsearch_data *__htab,
 		     const char *__env, size_t __size, const char __sep,
-		     int __flag, int nvars, char * const vars[], int do_apply);
+		     int __flag, int nvars, char * const vars[]);
 
-/* Flags for himport_r() */
-#define	H_NOCLEAR	(1 << 0) /* do not clear hash table before importing */
-#define	H_FORCE		(1 << 1) /* overwrite read-only/write-once variables */
+/* Flags for himport_r(), hdelete_r(), and hsearch_r() */
+#define H_NOCLEAR	(1 << 0) /* do not clear hash table before importing */
+#define H_FORCE		(1 << 1) /* overwrite read-only/write-once variables */
+#define H_INTERACTIVE	(1 << 2) /* indicate that an import is user directed */
 
 #endif /* search.h */
diff --git a/lib/hashtable.c b/lib/hashtable.c
index 94a7b61..f0056ac 100644
--- a/lib/hashtable.c
+++ b/lib/hashtable.c
@@ -142,7 +142,7 @@ int hcreate_r(size_t nel, struct hsearch_data *htab)
  * be freed and the local static variable can be marked as not used.
  */
 
-void hdestroy_r(struct hsearch_data *htab, int do_apply)
+void hdestroy_r(struct hsearch_data *htab)
 {
 	int i;
 
@@ -156,10 +156,7 @@ void hdestroy_r(struct hsearch_data *htab, int do_apply)
 	for (i = 1; i <= htab->size; ++i) {
 		if (htab->table[i].used > 0) {
 			ENTRY *ep = &htab->table[i].entry;
-			if (do_apply && htab->apply != NULL) {
-				/* deletion is always forced */
-				htab->apply(ep->key, ep->data, NULL, H_FORCE);
-			}
+
 			free((void *)ep->key);
 			free(ep->data);
 		}
@@ -251,7 +248,7 @@ int hmatch_r(const char *match, int last_idx, ENTRY ** retval,
 }
 
 int hsearch_r(ENTRY item, ACTION action, ENTRY ** retval,
-	      struct hsearch_data *htab)
+	      struct hsearch_data *htab, int flag)
 {
 	unsigned int hval;
 	unsigned int count;
@@ -404,7 +401,7 @@ int hsearch_r(ENTRY item, ACTION action, ENTRY ** retval,
  * do that.
  */
 
-int hdelete_r(const char *key, struct hsearch_data *htab, int do_apply)
+int hdelete_r(const char *key, struct hsearch_data *htab, int flag)
 {
 	ENTRY e, *ep;
 	int idx;
@@ -413,15 +410,21 @@ int hdelete_r(const char *key, struct hsearch_data *htab, int do_apply)
 
 	e.key = (char *)key;
 
-	if ((idx = hsearch_r(e, FIND, &ep, htab)) == 0) {
+	idx = hsearch_r(e, FIND, &ep, htab, 0);
+	if (idx == 0) {
 		__set_errno(ESRCH);
 		return 0;	/* not found */
 	}
 
+	/* Check for permission */
+	if (htab->apply != NULL &&
+	    htab->apply(ep->key, ep->data, NULL, flag)) {
+		__set_errno(EPERM);
+		return 0;
+	}
+
 	/* free used ENTRY */
 	debug("hdelete: DELETING key \"%s\"\n", key);
-	if (do_apply && htab->apply != NULL)
-		htab->apply(ep->key, ep->data, NULL, H_FORCE);
 	free((void *)ep->key);
 	free(ep->data);
 	htab->table[idx].used = -1;
@@ -674,7 +677,7 @@ static int drop_var_from_set(const char *name, int nvars, char * vars[])
 
 int himport_r(struct hsearch_data *htab,
 		const char *env, size_t size, const char sep, int flag,
-		int nvars, char * const vars[], int do_apply)
+		int nvars, char * const vars[])
 {
 	char *data, *sp, *dp, *name, *value;
 	char *localvars[nvars];
@@ -704,7 +707,7 @@ int himport_r(struct hsearch_data *htab,
 		debug("Destroy Hash Table: %p table = %p\n", htab,
 		       htab->table);
 		if (htab->table)
-			hdestroy_r(htab, do_apply);
+			hdestroy_r(htab);
 	}
 
 	/*
@@ -770,7 +773,7 @@ int himport_r(struct hsearch_data *htab,
 			if (!drop_var_from_set(name, nvars, localvars))
 				continue;
 
-			if (hdelete_r(name, htab, do_apply) == 0)
+			if (hdelete_r(name, htab, flag) == 0)
 				debug("DELETE ERROR ##############################\n");
 
 			continue;
@@ -795,14 +798,14 @@ int himport_r(struct hsearch_data *htab,
 		e.data = value;
 
 		/* if there is an apply function, check what it has to say */
-		if (do_apply && htab->apply != NULL) {
+		if (htab->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);
+			hsearch_r(e, FIND, &rv, htab, 0);
 			debug("previous value was %s\n", rv ? rv->data : "");
 			if (htab->apply(name, rv ? rv->data : NULL,
 				value, flag)) {
@@ -812,7 +815,7 @@ int himport_r(struct hsearch_data *htab,
 			}
 		}
 
-		hsearch_r(e, ENTER, &rv, htab);
+		hsearch_r(e, ENTER, &rv, htab, flag);
 		if (rv == NULL) {
 			printf("himport_r: can't insert \"%s=%s\" into hash table\n",
 				name, value);
@@ -839,7 +842,7 @@ int himport_r(struct hsearch_data *htab,
 		 * b) if the variable was not present in current env, we notify
 		 *    it might be a typo
 		 */
-		if (hdelete_r(localvars[i], htab, do_apply) == 0)
+		if (hdelete_r(localvars[i], htab, flag) == 0)
 			printf("WARNING: '%s' neither in running nor in imported env!\n", localvars[i]);
 		else
 			printf("WARNING: '%s' not in imported env, deleting it!\n", localvars[i]);
-- 
1.7.11.5

^ permalink raw reply related	[flat|nested] 124+ messages in thread

* [U-Boot] [PATCH v4 03/20] env: Consolidate common code in hsearch_r()
  2012-12-05  1:52                                         ` [U-Boot] [PATCH v4 0/20] " Joe Hershberger
  2012-12-05  1:52                                           ` [U-Boot] [PATCH v4 01/20] Make linux kernel string funcs available to tools Joe Hershberger
  2012-12-05  1:52                                           ` [U-Boot] [PATCH v4 02/20] env: Refactor do_apply to a flag Joe Hershberger
@ 2012-12-05  1:52                                           ` Joe Hershberger
  2012-12-05  1:52                                           ` [U-Boot] [PATCH v4 04/20] env: Refactor apply into change_ok Joe Hershberger
                                                             ` (18 subsequent siblings)
  21 siblings, 0 replies; 124+ messages in thread
From: Joe Hershberger @ 2012-12-05  1:52 UTC (permalink / raw)
  To: u-boot

The same chunk of code was replicated in two places and the following
changes will make that chunk grow a bit, so combine into a static func.

Signed-off-by: Joe Hershberger <joe.hershberger@ni.com>
---
Changes in v4: None
Changes in v3: None
Changes in v2: None

 lib/hashtable.c | 71 ++++++++++++++++++++++++++++++---------------------------
 1 file changed, 37 insertions(+), 34 deletions(-)

diff --git a/lib/hashtable.c b/lib/hashtable.c
index f0056ac..f4d5795 100644
--- a/lib/hashtable.c
+++ b/lib/hashtable.c
@@ -247,6 +247,34 @@ int hmatch_r(const char *match, int last_idx, ENTRY ** retval,
 	return 0;
 }
 
+/*
+ * Compare an existing entry with the desired key, and overwrite if the action
+ * is ENTER.  This is simply a helper function for hsearch_r().
+ */
+static inline int _compare_and_overwrite_entry(ENTRY item, ACTION action,
+	ENTRY **retval, struct hsearch_data *htab, int flag,
+	unsigned int hval, unsigned int idx)
+{
+	if (htab->table[idx].used == hval
+	    && strcmp(item.key, htab->table[idx].entry.key) == 0) {
+		/* Overwrite existing value? */
+		if ((action == ENTER) && (item.data != NULL)) {
+			free(htab->table[idx].entry.data);
+			htab->table[idx].entry.data = strdup(item.data);
+			if (!htab->table[idx].entry.data) {
+				__set_errno(ENOMEM);
+				*retval = NULL;
+				return 0;
+			}
+		}
+		/* return found entry */
+		*retval = &htab->table[idx].entry;
+		return idx;
+	}
+	/* keep searching */
+	return -1;
+}
+
 int hsearch_r(ENTRY item, ACTION action, ENTRY ** retval,
 	      struct hsearch_data *htab, int flag)
 {
@@ -255,6 +283,7 @@ int hsearch_r(ENTRY item, ACTION action, ENTRY ** retval,
 	unsigned int len = strlen(item.key);
 	unsigned int idx;
 	unsigned int first_deleted = 0;
+	int ret;
 
 	/* Compute an value for the given string. Perhaps use a better method. */
 	hval = len;
@@ -286,23 +315,10 @@ int hsearch_r(ENTRY item, ACTION action, ENTRY ** retval,
 		    && !first_deleted)
 			first_deleted = idx;
 
-		if (htab->table[idx].used == hval
-		    && strcmp(item.key, htab->table[idx].entry.key) == 0) {
-			/* Overwrite existing value? */
-			if ((action == ENTER) && (item.data != NULL)) {
-				free(htab->table[idx].entry.data);
-				htab->table[idx].entry.data =
-					strdup(item.data);
-				if (!htab->table[idx].entry.data) {
-					__set_errno(ENOMEM);
-					*retval = NULL;
-					return 0;
-				}
-			}
-			/* return found entry */
-			*retval = &htab->table[idx].entry;
-			return idx;
-		}
+		ret = _compare_and_overwrite_entry(item, action, retval, htab,
+			flag, hval, idx);
+		if (ret != -1)
+			return ret;
 
 		/*
 		 * Second hash function:
@@ -328,23 +344,10 @@ int hsearch_r(ENTRY item, ACTION action, ENTRY ** retval,
 				break;
 
 			/* If entry is found use it. */
-			if ((htab->table[idx].used == hval)
-			    && strcmp(item.key, htab->table[idx].entry.key) == 0) {
-				/* Overwrite existing value? */
-				if ((action == ENTER) && (item.data != NULL)) {
-					free(htab->table[idx].entry.data);
-					htab->table[idx].entry.data =
-						strdup(item.data);
-					if (!htab->table[idx].entry.data) {
-						__set_errno(ENOMEM);
-						*retval = NULL;
-						return 0;
-					}
-				}
-				/* return found entry */
-				*retval = &htab->table[idx].entry;
-				return idx;
-			}
+			ret = _compare_and_overwrite_entry(item, action, retval,
+				htab, flag, hval, idx);
+			if (ret != -1)
+				return ret;
 		}
 		while (htab->table[idx].used);
 	}
-- 
1.7.11.5

^ permalink raw reply related	[flat|nested] 124+ messages in thread

* [U-Boot] [PATCH v4 04/20] env: Refactor apply into change_ok
  2012-12-05  1:52                                         ` [U-Boot] [PATCH v4 0/20] " Joe Hershberger
                                                             ` (2 preceding siblings ...)
  2012-12-05  1:52                                           ` [U-Boot] [PATCH v4 03/20] env: Consolidate common code in hsearch_r() Joe Hershberger
@ 2012-12-05  1:52                                           ` Joe Hershberger
  2012-12-05  1:52                                           ` [U-Boot] [PATCH v4 05/20] env: Use getenv_yesno() more generally Joe Hershberger
                                                             ` (17 subsequent siblings)
  21 siblings, 0 replies; 124+ messages in thread
From: Joe Hershberger @ 2012-12-05  1:52 UTC (permalink / raw)
  To: u-boot

Move the read of the old value to inside the check function.  In some
cases it can be avoided all together and at the least the code is only
called from one place.

Also name the function and the callback to more clearly describe what
it does.

Pass the ENTRY instead of just the name for direct access to the whole
data structure.

Pass an enum to the callback that specifies the operation being approved.

Signed-off-by: Joe Hershberger <joe.hershberger@ni.com>
---
Changes in v4: None
Changes in v3:
- Split hdelete_r() into the core delete and the validation before
delete
- Delete vars on failed insertion

Changes in v2: None

 common/cmd_nvedit.c   | 34 +++++++++++--------------
 common/env_common.c   |  2 +-
 include/environment.h |  7 +++---
 include/search.h      | 13 +++++++---
 lib/hashtable.c       | 70 +++++++++++++++++++++++++++++++--------------------
 5 files changed, 71 insertions(+), 55 deletions(-)

diff --git a/common/cmd_nvedit.c b/common/cmd_nvedit.c
index a8dc9a6..da5689c 100644
--- a/common/cmd_nvedit.c
+++ b/common/cmd_nvedit.c
@@ -208,10 +208,20 @@ static int do_env_grep(cmd_tbl_t *cmdtp, int flag,
  * overwriting of write-once variables.
  */
 
-int env_check_apply(const char *name, const char *oldval,
-			const char *newval, int flag)
+int env_change_ok(const ENTRY *item, const char *newval, enum env_op op,
+	int flag)
 {
 	int   console = -1;
+	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 ? : "";
@@ -242,12 +252,12 @@ int env_check_apply(const char *name, const char *oldval,
 #endif /* CONFIG_CONSOLE_MUX */
 	}
 
+#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.
 	 */
-#ifndef CONFIG_ENV_OVERWRITE
-	if (oldval != NULL &&			/* variable exists */
+	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
@@ -265,7 +275,7 @@ int env_check_apply(const char *name, const char *oldval,
 	 * (which will erase all variables prior to calling this),
 	 * we want the baudrate to actually change - for real.
 	 */
-	if (oldval != NULL ||			/* variable exists */
+	if (op != env_op_create ||		/* variable exists */
 		(flag & H_NOCLEAR) == 0) {	/* or env is clear */
 		/*
 		 * Switch to new baudrate if new baudrate is supported
@@ -339,20 +349,6 @@ static int _do_env_set(int flag, int argc, char * const argv[])
 	}
 
 	env_id++;
-	/*
-	 * search if variable with this name already exists
-	 */
-	e.key = name;
-	e.data = NULL;
-	hsearch_r(e, FIND, &ep, &env_htab, 0);
-
-	/*
-	 * Perform requested checks.
-	 */
-	if (env_check_apply(name, ep ? ep->data : NULL, value, 0)) {
-		debug("check function did not approve, refusing\n");
-		return 1;
-	}
 
 	/* Delete only ? */
 	if (argc < 3 || argv[2] == NULL) {
diff --git a/common/env_common.c b/common/env_common.c
index f22f5b9..919f535 100644
--- a/common/env_common.c
+++ b/common/env_common.c
@@ -40,7 +40,7 @@ DECLARE_GLOBAL_DATA_PTR;
 #include <env_default.h>
 
 struct hsearch_data env_htab = {
-	.apply = env_check_apply,
+	.change_ok = env_change_ok,
 };
 
 static uchar __env_get_char_spec(int index)
diff --git a/include/environment.h b/include/environment.h
index e8ab703..4b19f32 100644
--- a/include/environment.h
+++ b/include/environment.h
@@ -188,13 +188,12 @@ int set_default_vars(int nvars, char * const vars[]);
 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).
+ * Check if variable "item" can be changed to newval
  * When (flag & H_FORCE) is set, it does not print out any error
  * message and forces overwriting of write-once variables.
  */
-int env_check_apply(const char *name, const char *oldval,
-			const char *newval, int flag);
+int env_change_ok(const ENTRY *item, const char *newval, enum env_op op,
+	int flag);
 
 #endif /* DO_DEPS_ONLY */
 
diff --git a/include/search.h b/include/search.h
index f5165b0..fa00ea1 100644
--- a/include/search.h
+++ b/include/search.h
@@ -32,6 +32,12 @@
 
 #define __set_errno(val) do { errno = val; } while (0)
 
+enum env_op {
+	env_op_create,
+	env_op_delete,
+	env_op_overwrite,
+};
+
 /* Action which shall be performed in the call the hsearch.  */
 typedef enum {
 	FIND,
@@ -59,14 +65,13 @@ struct hsearch_data {
 	unsigned int filled;
 /*
  * Callback function which will check whether the given change for variable
- * "name" from "oldval" to "newval" may be applied or not, and possibly apply
- * such change.
+ * "item" to "newval" may be applied or not, and possibly apply such change.
  * When (flag & H_FORCE) is set, it shall not print out any error message and
  * shall force overwriting of write-once variables.
 .* Must return 0 for approval, 1 for denial.
  */
-	int (*apply)(const char *name, const char *oldval,
-			const char *newval, int flag);
+	int (*change_ok)(const ENTRY *__item, const char *newval, enum env_op,
+		int flag);
 };
 
 /* Create a new hashing table which will at most contain NEL elements.  */
diff --git a/lib/hashtable.c b/lib/hashtable.c
index f4d5795..6861a42 100644
--- a/lib/hashtable.c
+++ b/lib/hashtable.c
@@ -66,12 +66,16 @@
  * Instead the interface of all functions is extended to take an argument
  * which describes the current status.
  */
+
 typedef struct _ENTRY {
 	int used;
 	ENTRY entry;
 } _ENTRY;
 
 
+static void _hdelete(const char *key, struct hsearch_data *htab, ENTRY *ep,
+	int idx);
+
 /*
  * hcreate()
  */
@@ -259,6 +263,17 @@ static inline int _compare_and_overwrite_entry(ENTRY item, ACTION action,
 	    && strcmp(item.key, htab->table[idx].entry.key) == 0) {
 		/* Overwrite existing value? */
 		if ((action == ENTER) && (item.data != NULL)) {
+			/* check for permission */
+			if (htab->change_ok != NULL && htab->change_ok(
+			    &htab->table[idx].entry, item.data,
+			    env_op_overwrite, flag)) {
+				debug("change_ok() rejected setting variable "
+					"%s, skipping it!\n", item.key);
+				__set_errno(EPERM);
+				*retval = NULL;
+				return 0;
+			}
+
 			free(htab->table[idx].entry.data);
 			htab->table[idx].entry.data = strdup(item.data);
 			if (!htab->table[idx].entry.data) {
@@ -383,6 +398,17 @@ int hsearch_r(ENTRY item, ACTION action, ENTRY ** retval,
 
 		++htab->filled;
 
+		/* check for permission */
+		if (htab->change_ok != NULL && htab->change_ok(
+		    &htab->table[idx].entry, item.data, env_op_create, flag)) {
+			debug("change_ok() rejected setting variable "
+				"%s, skipping it!\n", item.key);
+			_hdelete(item.key, htab, &htab->table[idx].entry, idx);
+			__set_errno(EPERM);
+			*retval = NULL;
+			return 0;
+		}
+
 		/* return new entry */
 		*retval = &htab->table[idx].entry;
 		return 1;
@@ -404,6 +430,18 @@ int hsearch_r(ENTRY item, ACTION action, ENTRY ** retval,
  * do that.
  */
 
+static void _hdelete(const char *key, struct hsearch_data *htab, ENTRY *ep,
+	int idx)
+{
+	/* free used ENTRY */
+	debug("hdelete: DELETING key \"%s\"\n", key);
+	free((void *)ep->key);
+	free(ep->data);
+	htab->table[idx].used = -1;
+
+	--htab->filled;
+}
+
 int hdelete_r(const char *key, struct hsearch_data *htab, int flag)
 {
 	ENTRY e, *ep;
@@ -420,19 +458,15 @@ int hdelete_r(const char *key, struct hsearch_data *htab, int flag)
 	}
 
 	/* Check for permission */
-	if (htab->apply != NULL &&
-	    htab->apply(ep->key, ep->data, NULL, flag)) {
+	if (htab->change_ok != NULL &&
+	    htab->change_ok(ep, NULL, env_op_delete, flag)) {
+		debug("change_ok() rejected deleting variable "
+			"%s, skipping it!\n", key);
 		__set_errno(EPERM);
 		return 0;
 	}
 
-	/* free used ENTRY */
-	debug("hdelete: DELETING key \"%s\"\n", key);
-	free((void *)ep->key);
-	free(ep->data);
-	htab->table[idx].used = -1;
-
-	--htab->filled;
+	_hdelete(key, htab, ep, idx);
 
 	return 1;
 }
@@ -800,24 +834,6 @@ int himport_r(struct hsearch_data *htab,
 		e.key = name;
 		e.data = value;
 
-		/* if there is an apply function, check what it has to say */
-		if (htab->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, 0);
-			debug("previous value was %s\n", rv ? rv->data : "");
-			if (htab->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, flag);
 		if (rv == NULL) {
 			printf("himport_r: can't insert \"%s=%s\" into hash table\n",
-- 
1.7.11.5

^ permalink raw reply related	[flat|nested] 124+ messages in thread

* [U-Boot] [PATCH v4 05/20] env: Use getenv_yesno() more generally
  2012-12-05  1:52                                         ` [U-Boot] [PATCH v4 0/20] " Joe Hershberger
                                                             ` (3 preceding siblings ...)
  2012-12-05  1:52                                           ` [U-Boot] [PATCH v4 04/20] env: Refactor apply into change_ok Joe Hershberger
@ 2012-12-05  1:52                                           ` Joe Hershberger
  2012-12-05  1:52                                           ` [U-Boot] [PATCH v4 06/20] env: Hide '.' variables in env print by default Joe Hershberger
                                                             ` (16 subsequent siblings)
  21 siblings, 0 replies; 124+ messages in thread
From: Joe Hershberger @ 2012-12-05  1:52 UTC (permalink / raw)
  To: u-boot

Move the getenv_yesno() to env_common.c and change most checks for
'y' or 'n' to use this helper.

Signed-off-by: Joe Hershberger <joe.hershberger@ni.com>
---
Changes in v4: None
Changes in v3: None
Changes in v2: None

 arch/arm/lib/board.c            |  4 +---
 arch/m68k/lib/board.c           |  3 +--
 arch/microblaze/lib/board.c     |  4 +---
 arch/powerpc/cpu/mpc85xx/mp.c   |  4 +---
 arch/powerpc/lib/board.c        |  9 ++-------
 arch/sparc/lib/board.c          |  3 +--
 board/Marvell/db64360/db64360.c | 10 +++-------
 board/Marvell/db64460/db64460.c | 10 +++-------
 board/esd/cpci750/cpci750.c     | 10 +++-------
 board/gw8260/gw8260.c           | 10 +++-------
 board/prodrive/p3mx/p3mx.c      | 10 +++-------
 common/env_common.c             | 14 ++++++++++++++
 common/image.c                  |  6 ------
 include/common.h                |  5 +++++
 include/image.h                 |  1 -
 net/net.c                       | 32 +++++++++++++++-----------------
 16 files changed, 56 insertions(+), 79 deletions(-)

diff --git a/arch/arm/lib/board.c b/arch/arm/lib/board.c
index 22a4d9c..e0cb635 100644
--- a/arch/arm/lib/board.c
+++ b/arch/arm/lib/board.c
@@ -540,15 +540,13 @@ void board_init_r(gd_t *id, ulong dest_addr)
 	flash_size = flash_init();
 	if (flash_size > 0) {
 # ifdef CONFIG_SYS_FLASH_CHECKSUM
-		char *s = getenv("flashchecksum");
-
 		print_size(flash_size, "");
 		/*
 		 * Compute and print flash CRC if flashchecksum is set to 'y'
 		 *
 		 * NOTE: Maybe we should add some WATCHDOG_RESET()? XXX
 		 */
-		if (s && (*s == 'y')) {
+		if (getenv_yesno("flashchecksum") == 1) {
 			printf("  CRC: %08X", crc32(0,
 				(const unsigned char *) CONFIG_SYS_FLASH_BASE,
 				flash_size));
diff --git a/arch/m68k/lib/board.c b/arch/m68k/lib/board.c
index 02d73fd..794b867 100644
--- a/arch/m68k/lib/board.c
+++ b/arch/m68k/lib/board.c
@@ -462,8 +462,7 @@ void board_init_r (gd_t *id, ulong dest_addr)
 		 *
 		 * NOTE: Maybe we should add some WATCHDOG_RESET()? XXX
 		 */
-		s = getenv ("flashchecksum");
-		if (s && (*s == 'y')) {
+		if (getenv_yesno("flashchecksum") == 1) {
 			printf ("  CRC: %08X",
 					crc32 (0,
 						   (const unsigned char *) CONFIG_SYS_FLASH_BASE,
diff --git a/arch/microblaze/lib/board.c b/arch/microblaze/lib/board.c
index efd63cd..a7c2f76 100644
--- a/arch/microblaze/lib/board.c
+++ b/arch/microblaze/lib/board.c
@@ -74,7 +74,6 @@ void board_init_f(ulong not_used)
 	gd = (gd_t *) (CONFIG_SYS_SDRAM_BASE + CONFIG_SYS_GBL_DATA_OFFSET);
 	bd = (bd_t *) (CONFIG_SYS_SDRAM_BASE + CONFIG_SYS_GBL_DATA_OFFSET \
 						- GENERATED_BD_INFO_SIZE);
-	__maybe_unused char *s;
 #if defined(CONFIG_CMD_FLASH)
 	ulong flash_size = 0;
 #endif
@@ -143,8 +142,7 @@ void board_init_f(ulong not_used)
 		 *
 		 * NOTE: Maybe we should add some WATCHDOG_RESET()? XXX
 		 */
-		s = getenv ("flashchecksum");
-		if (s && (*s == 'y')) {
+		if (getenv_yesno("flashchecksum") == 1) {
 			printf ("  CRC: %08X",
 				crc32(0, (const u8 *)bd->bi_flashstart,
 							flash_size)
diff --git a/arch/powerpc/cpu/mpc85xx/mp.c b/arch/powerpc/cpu/mpc85xx/mp.c
index e1197ac..43d4836 100644
--- a/arch/powerpc/cpu/mpc85xx/mp.c
+++ b/arch/powerpc/cpu/mpc85xx/mp.c
@@ -46,10 +46,8 @@ u32 get_my_id()
  */
 int hold_cores_in_reset(int verbose)
 {
-	const char *s = getenv("mp_holdoff");
-
 	/* Default to no, overriden by 'y', 'yes', 'Y', 'Yes', or '1' */
-	if (s && (*s == 'y' || *s == 'Y' || *s == '1')) {
+	if (getenv_yesno("mp_holdoff") == 1) {
 		if (verbose) {
 			puts("Secondary cores are being held in reset.\n");
 			puts("See 'mp_holdoff' environment variable\n");
diff --git a/arch/powerpc/lib/board.c b/arch/powerpc/lib/board.c
index 1b051e1..6a7bf4b 100644
--- a/arch/powerpc/lib/board.c
+++ b/arch/powerpc/lib/board.c
@@ -739,16 +739,13 @@ void board_init_r(gd_t *id, ulong dest_addr)
 		flash_size = 0;
 	} else if ((flash_size = flash_init()) > 0) {
 #ifdef CONFIG_SYS_FLASH_CHECKSUM
-		char *s;
-
 		print_size(flash_size, "");
 		/*
 		 * Compute and print flash CRC if flashchecksum is set to 'y'
 		 *
 		 * NOTE: Maybe we should add some WATCHDOG_RESET()? XXX
 		 */
-		s = getenv("flashchecksum");
-		if (s && (*s == 'y')) {
+		if (getenv_yesno("flashchecksum") == 1) {
 			printf("  CRC: %08X",
 			       crc32(0,
 				     (const unsigned char *)
@@ -841,9 +838,7 @@ void board_init_r(gd_t *id, ulong dest_addr)
 	 * "i2cfast" into account
 	 */
 	{
-		char *s = getenv("i2cfast");
-
-		if (s && ((*s == 'y') || (*s == 'Y'))) {
+		if (getenv_yesno("i2cfast") == 1) {
 			bd->bi_iic_fast[0] = 1;
 			bd->bi_iic_fast[1] = 1;
 		}
diff --git a/arch/sparc/lib/board.c b/arch/sparc/lib/board.c
index 32d025a..1b5e995 100644
--- a/arch/sparc/lib/board.c
+++ b/arch/sparc/lib/board.c
@@ -284,8 +284,7 @@ void board_init_f(ulong bootflag)
 		 *
 		 * NOTE: Maybe we should add some WATCHDOG_RESET()? XXX
 		 */
-		s = getenv("flashchecksum");
-		if (s && (*s == 'y')) {
+		if (getenv_yesno("flashchecksum") == 1) {
 			printf("  CRC: %08lX",
 			       crc32(0, (const unsigned char *)CONFIG_SYS_FLASH_BASE,
 				     flash_size)
diff --git a/board/Marvell/db64360/db64360.c b/board/Marvell/db64360/db64360.c
index 6cae686..38769e0 100644
--- a/board/Marvell/db64360/db64360.c
+++ b/board/Marvell/db64360/db64360.c
@@ -834,15 +834,11 @@ int mem_test_walk (void)
 /*********************************************************************/
 int testdram (void)
 {
-	char *s;
 	int rundata, runaddress, runwalk;
 
-	s = getenv ("testdramdata");
-	rundata = (s && (*s == 'y')) ? 1 : 0;
-	s = getenv ("testdramaddress");
-	runaddress = (s && (*s == 'y')) ? 1 : 0;
-	s = getenv ("testdramwalk");
-	runwalk = (s && (*s == 'y')) ? 1 : 0;
+	rundata = getenv_yesno("testdramdata") == 1;
+	runaddress = getenv_yesno("testdramaddress") == 1;
+	runwalk = getenv_yesno("testdramwalk") == 1;
 
 /*    rundata = 1; */
 /*    runaddress = 0; */
diff --git a/board/Marvell/db64460/db64460.c b/board/Marvell/db64460/db64460.c
index d4f58b3..ddb7ed5 100644
--- a/board/Marvell/db64460/db64460.c
+++ b/board/Marvell/db64460/db64460.c
@@ -834,15 +834,11 @@ int mem_test_walk (void)
 /*********************************************************************/
 int testdram (void)
 {
-	char *s;
 	int rundata, runaddress, runwalk;
 
-	s = getenv ("testdramdata");
-	rundata = (s && (*s == 'y')) ? 1 : 0;
-	s = getenv ("testdramaddress");
-	runaddress = (s && (*s == 'y')) ? 1 : 0;
-	s = getenv ("testdramwalk");
-	runwalk = (s && (*s == 'y')) ? 1 : 0;
+	rundata = getenv_yesno("testdramdata") == 1;
+	runaddress = getenv_yesno("testdramaddress") == 1;
+	runwalk = getenv_yesno("testdramwalk") == 1;
 
 /*    rundata = 1; */
 /*    runaddress = 0; */
diff --git a/board/esd/cpci750/cpci750.c b/board/esd/cpci750/cpci750.c
index 98051fb..d7deae4 100644
--- a/board/esd/cpci750/cpci750.c
+++ b/board/esd/cpci750/cpci750.c
@@ -953,22 +953,18 @@ int mem_test_walk (void)
 /*********************************************************************/
 int testdram (void)
 {
-	char *s;
 	int rundata    = 0;
 	int runaddress = 0;
 	int runwalk    = 0;
 
 #ifdef CONFIG_SYS_DRAM_TEST_DATA
-	s = getenv ("testdramdata");
-	rundata = (s && (*s == 'y')) ? 1 : 0;
+	rundata = getenv_yesno("testdramdata") == 1;
 #endif
 #ifdef CONFIG_SYS_DRAM_TEST_ADDRESS
-	s = getenv ("testdramaddress");
-	runaddress = (s && (*s == 'y')) ? 1 : 0;
+	runaddress = getenv_yesno("testdramaddress") == 1;
 #endif
 #ifdef CONFIG_SYS_DRAM_TEST_WALK
-	s = getenv ("testdramwalk");
-	runwalk = (s && (*s == 'y')) ? 1 : 0;
+	runwalk = getenv_yesno("testdramwalk") == 1;
 #endif
 
 	if ((rundata == 1) || (runaddress == 1) || (runwalk == 1)) {
diff --git a/board/gw8260/gw8260.c b/board/gw8260/gw8260.c
index 77a1e1d..64c54d5 100644
--- a/board/gw8260/gw8260.c
+++ b/board/gw8260/gw8260.c
@@ -544,15 +544,11 @@ int mem_test_walk (void)
 /*********************************************************************/
 int testdram (void)
 {
-	char *s;
 	int rundata, runaddress, runwalk;
 
-	s = getenv ("testdramdata");
-	rundata = (s && (*s == 'y')) ? 1 : 0;
-	s = getenv ("testdramaddress");
-	runaddress = (s && (*s == 'y')) ? 1 : 0;
-	s = getenv ("testdramwalk");
-	runwalk = (s && (*s == 'y')) ? 1 : 0;
+	rundata = getenv_yesno("testdramdata") == 1;
+	runaddress = getenv_yesno("testdramaddress") == 1;
+	runwalk = getenv_yesno("testdramwalk") == 1;
 
 	if ((rundata == 1) || (runaddress == 1) || (runwalk == 1)) {
 		printf ("Testing RAM ... ");
diff --git a/board/prodrive/p3mx/p3mx.c b/board/prodrive/p3mx/p3mx.c
index 389affc..c3fd191 100644
--- a/board/prodrive/p3mx/p3mx.c
+++ b/board/prodrive/p3mx/p3mx.c
@@ -768,22 +768,18 @@ int mem_test_walk (void)
 /*********************************************************************/
 int testdram (void)
 {
-	char *s;
 	int rundata    = 0;
 	int runaddress = 0;
 	int runwalk    = 0;
 
 #ifdef CONFIG_SYS_DRAM_TEST_DATA
-	s = getenv ("testdramdata");
-	rundata = (s && (*s == 'y')) ? 1 : 0;
+	rundata = getenv_yesno("testdramdata") == 1;
 #endif
 #ifdef CONFIG_SYS_DRAM_TEST_ADDRESS
-	s = getenv ("testdramaddress");
-	runaddress = (s && (*s == 'y')) ? 1 : 0;
+	runaddress = getenv_yesno("testdramaddress") == 1;
 #endif
 #ifdef CONFIG_SYS_DRAM_TEST_WALK
-	s = getenv ("testdramwalk");
-	runwalk = (s && (*s == 'y')) ? 1 : 0;
+	runwalk = getenv_yesno("testdramwalk") == 1;
 #endif
 
 	if ((rundata == 1) || (runaddress == 1) || (runwalk == 1))
diff --git a/common/env_common.c b/common/env_common.c
index 919f535..a86f061 100644
--- a/common/env_common.c
+++ b/common/env_common.c
@@ -81,6 +81,20 @@ const uchar *env_get_addr(int index)
 		return &default_environment[index];
 }
 
+/*
+ * Read an environment variable as a boolean
+ * Return -1 if variable does not exist (default to true)
+ */
+int getenv_yesno(const char *var)
+{
+	char *s = getenv(var);
+
+	if (s == NULL)
+		return -1;
+	return (*s == '1' || *s == 'y' || *s == 'Y' || *s == 't' || *s == 'T') ?
+		1 : 0;
+}
+
 void set_default_env(const char *s)
 {
 	int flags = 0;
diff --git a/common/image.c b/common/image.c
index e93b6e8..69e888c 100644
--- a/common/image.c
+++ b/common/image.c
@@ -416,12 +416,6 @@ static const image_header_t *image_get_ramdisk(ulong rd_addr, uint8_t arch,
 /* Shared dual-format routines */
 /*****************************************************************************/
 #ifndef USE_HOSTCC
-int getenv_yesno(char *var)
-{
-	char *s = getenv(var);
-	return (s && (*s == 'n')) ? 0 : 1;
-}
-
 ulong getenv_bootm_low(void)
 {
 	char *s = getenv("bootm_low");
diff --git a/include/common.h b/include/common.h
index 5e3c5ee..d0bf1e8 100644
--- a/include/common.h
+++ b/include/common.h
@@ -340,6 +340,11 @@ int	envmatch     (uchar *, int);
 char	*getenv	     (const char *);
 int	getenv_f     (const char *name, char *buf, unsigned len);
 ulong getenv_ulong(const char *name, int base, ulong default_val);
+/*
+ * Read an environment variable as a boolean
+ * Return -1 if variable does not exist (default to true)
+ */
+int getenv_yesno(const char *var);
 int	saveenv	     (void);
 int	setenv	     (const char *, const char *);
 int setenv_ulong(const char *varname, ulong value);
diff --git a/include/image.h b/include/image.h
index f54d983..b958b18 100644
--- a/include/image.h
+++ b/include/image.h
@@ -460,7 +460,6 @@ static inline void image_set_name(image_header_t *hdr, const char *name)
 int image_check_hcrc(const image_header_t *hdr);
 int image_check_dcrc(const image_header_t *hdr);
 #ifndef USE_HOSTCC
-int getenv_yesno(char *var);
 ulong getenv_bootm_low(void);
 phys_size_t getenv_bootm_size(void);
 phys_size_t getenv_bootm_mapsize(void);
diff --git a/net/net.c b/net/net.c
index 82c4cc9..da68a61 100644
--- a/net/net.c
+++ b/net/net.c
@@ -214,26 +214,24 @@ static int NetTryCount;
  */
 void net_auto_load(void)
 {
+#if defined(CONFIG_CMD_NFS)
 	const char *s = getenv("autoload");
 
-	if (s != NULL) {
-		if (*s == 'n') {
-			/*
-			 * Just use BOOTP/RARP to configure system;
-			 * Do not use TFTP to load the bootfile.
-			 */
-			net_set_state(NETLOOP_SUCCESS);
-			return;
-		}
-#if defined(CONFIG_CMD_NFS)
-		if (strcmp(s, "NFS") == 0) {
-			/*
-			 * Use NFS to load the bootfile.
-			 */
-			NfsStart();
-			return;
-		}
+	if (s != NULL && strcmp(s, "NFS") == 0) {
+		/*
+		 * Use NFS to load the bootfile.
+		 */
+		NfsStart();
+		return;
+	}
 #endif
+	if (getenv_yesno("autoload") == 0) {
+		/*
+		 * Just use BOOTP/RARP to configure system;
+		 * Do not use TFTP to load the bootfile.
+		 */
+		net_set_state(NETLOOP_SUCCESS);
+		return;
 	}
 	TftpStart(TFTPGET);
 }
-- 
1.7.11.5

^ permalink raw reply related	[flat|nested] 124+ messages in thread

* [U-Boot] [PATCH v4 06/20] env: Hide '.' variables in env print by default
  2012-12-05  1:52                                         ` [U-Boot] [PATCH v4 0/20] " Joe Hershberger
                                                             ` (4 preceding siblings ...)
  2012-12-05  1:52                                           ` [U-Boot] [PATCH v4 05/20] env: Use getenv_yesno() more generally Joe Hershberger
@ 2012-12-05  1:52                                           ` Joe Hershberger
  2012-12-05  1:52                                           ` [U-Boot] [PATCH v4 07/20] env: Add support for callbacks to environment vars Joe Hershberger
                                                             ` (15 subsequent siblings)
  21 siblings, 0 replies; 124+ messages in thread
From: Joe Hershberger @ 2012-12-05  1:52 UTC (permalink / raw)
  To: u-boot

When printing all variables with env print, don't print variables that
begin with '.'.  If env print is called with a '-a' switch, then
include variables that begin with '.' (just like the ls command).

Variables printed explicitly will be printed even without the -a.

Signed-off-by: Joe Hershberger <joe.hershberger@ni.com>
---
Changes in v4:
- Fixed help text

Changes in v3: None
Changes in v2: None

 board/esd/pmc440/cmd_pmc440.c |  2 +-
 common/cmd_nvedit.c           | 26 +++++++++++++++++---------
 common/env_dataflash.c        |  2 +-
 common/env_eeprom.c           |  2 +-
 common/env_fat.c              |  2 +-
 common/env_flash.c            |  4 ++--
 common/env_mmc.c              |  2 +-
 common/env_nand.c             |  4 ++--
 common/env_nvram.c            |  2 +-
 common/env_onenand.c          |  2 +-
 common/env_sf.c               |  4 ++--
 include/search.h              |  5 +++--
 lib/hashtable.c               |  5 ++++-
 13 files changed, 37 insertions(+), 25 deletions(-)

diff --git a/board/esd/pmc440/cmd_pmc440.c b/board/esd/pmc440/cmd_pmc440.c
index f1ffb7b..e9a78a3 100644
--- a/board/esd/pmc440/cmd_pmc440.c
+++ b/board/esd/pmc440/cmd_pmc440.c
@@ -391,7 +391,7 @@ int do_painit(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
 	nextbase -= ((CONFIG_ENV_SIZE + 4096 - 1) & ~(4096 - 1));
 	envp = (env_t *)nextbase;
 	res = (char *)envp->data;
-	len = hexport_r(&env_htab, '\0', &res, ENV_SIZE, 0, NULL);
+	len = hexport_r(&env_htab, '\0', 0, &res, ENV_SIZE, 0, NULL);
 	if (len < 0) {
 		error("Cannot export environment: errno = %d\n", errno);
 		return 1;
diff --git a/common/cmd_nvedit.c b/common/cmd_nvedit.c
index da5689c..022ad39 100644
--- a/common/cmd_nvedit.c
+++ b/common/cmd_nvedit.c
@@ -106,7 +106,7 @@ int get_env_id(void)
  *
  * Returns 0 in case of error, or length of printed string
  */
-static int env_print(char *name)
+static int env_print(char *name, int flag)
 {
 	char *res = NULL;
 	size_t len;
@@ -116,7 +116,7 @@ static int env_print(char *name)
 
 		e.key = name;
 		e.data = NULL;
-		hsearch_r(e, FIND, &ep, &env_htab, 0);
+		hsearch_r(e, FIND, &ep, &env_htab, flag);
 		if (ep == NULL)
 			return 0;
 		len = printf("%s=%s\n", ep->key, ep->data);
@@ -124,7 +124,7 @@ static int env_print(char *name)
 	}
 
 	/* print whole list */
-	len = hexport_r(&env_htab, '\n', &res, 0, 0, NULL);
+	len = hexport_r(&env_htab, '\n', flag, &res, 0, 0, NULL);
 
 	if (len > 0) {
 		puts(res);
@@ -141,10 +141,17 @@ static int do_env_print(cmd_tbl_t *cmdtp, int flag, int argc,
 {
 	int i;
 	int rcode = 0;
+	int env_flag = H_HIDE_DOT;
+
+	if (argc > 1 && argv[1][0] == '-' && argv[1][1] == 'a') {
+		argc--;
+		argv++;
+		env_flag &= ~H_HIDE_DOT;
+	}
 
 	if (argc == 1) {
 		/* print all env vars */
-		rcode = env_print(NULL);
+		rcode = env_print(NULL, env_flag);
 		if (!rcode)
 			return 1;
 		printf("\nEnvironment size: %d/%ld bytes\n",
@@ -153,8 +160,9 @@ static int do_env_print(cmd_tbl_t *cmdtp, int flag, int argc,
 	}
 
 	/* print selected env vars */
+	env_flag &= ~H_HIDE_DOT;
 	for (i = 1; i < argc; ++i) {
-		int rc = env_print(argv[i]);
+		int rc = env_print(argv[i], env_flag);
 		if (!rc) {
 			printf("## Error: \"%s\" not defined\n", argv[i]);
 			++rcode;
@@ -807,7 +815,7 @@ NXTARG:		;
 	argv++;
 
 	if (sep) {		/* export as text file */
-		len = hexport_r(&env_htab, sep, &addr, size, argc, argv);
+		len = hexport_r(&env_htab, sep, 0, &addr, size, argc, argv);
 		if (len < 0) {
 			error("Cannot export environment: errno = %d\n", errno);
 			return 1;
@@ -825,7 +833,7 @@ NXTARG:		;
 	else			/* export as raw binary data */
 		res = addr;
 
-	len = hexport_r(&env_htab, '\0', &res, ENV_SIZE, argc, argv);
+	len = hexport_r(&env_htab, '\0', 0, &res, ENV_SIZE, argc, argv);
 	if (len < 0) {
 		error("Cannot export environment: errno = %d\n", errno);
 		return 1;
@@ -1037,7 +1045,7 @@ static char env_help_text[] =
 #if defined(CONFIG_CMD_IMPORTENV)
 	"env import [-d] [-t | -b | -c] addr [size] - import environment\n"
 #endif
-	"env print [name ...] - print environment\n"
+	"env print [-a | name ...] - print environment\n"
 #if defined(CONFIG_CMD_RUN)
 	"env run var [...] - run commands in an environment variable\n"
 #endif
@@ -1069,7 +1077,7 @@ U_BOOT_CMD_COMPLETE(
 U_BOOT_CMD_COMPLETE(
 	printenv, CONFIG_SYS_MAXARGS, 1,	do_env_print,
 	"print environment variables",
-	"\n    - print values of all environment variables\n"
+	"[-a]\n    - print [all] values of all environment variables\n"
 	"printenv name ...\n"
 	"    - print value of environment variable 'name'",
 	var_complete
diff --git a/common/env_dataflash.c b/common/env_dataflash.c
index 3c5af37..38c9615 100644
--- a/common/env_dataflash.c
+++ b/common/env_dataflash.c
@@ -60,7 +60,7 @@ int saveenv(void)
 	char	*res;
 
 	res = (char *)&env_new.data;
-	len = hexport_r(&env_htab, '\0', &res, ENV_SIZE, 0, NULL);
+	len = hexport_r(&env_htab, '\0', 0, &res, ENV_SIZE, 0, NULL);
 	if (len < 0) {
 		error("Cannot export environment: errno = %d\n", errno);
 		return 1;
diff --git a/common/env_eeprom.c b/common/env_eeprom.c
index b66bba2..45c935b 100644
--- a/common/env_eeprom.c
+++ b/common/env_eeprom.c
@@ -139,7 +139,7 @@ int saveenv(void)
 	BUG_ON(env_ptr != NULL);
 
 	res = (char *)&env_new.data;
-	len = hexport_r(&env_htab, '\0', &res, ENV_SIZE, 0, NULL);
+	len = hexport_r(&env_htab, '\0', 0, &res, ENV_SIZE, 0, NULL);
 	if (len < 0) {
 		error("Cannot export environment: errno = %d\n", errno);
 		return 1;
diff --git a/common/env_fat.c b/common/env_fat.c
index 6ef5318..c0f18ab 100644
--- a/common/env_fat.c
+++ b/common/env_fat.c
@@ -61,7 +61,7 @@ int saveenv(void)
 	int err;
 
 	res = (char *)&env_new.data;
-	len = hexport_r(&env_htab, '\0', &res, ENV_SIZE, 0, NULL);
+	len = hexport_r(&env_htab, '\0', 0, &res, ENV_SIZE, 0, NULL);
 	if (len < 0) {
 		error("Cannot export environment: errno = %d\n", errno);
 		return 1;
diff --git a/common/env_flash.c b/common/env_flash.c
index aa970d4..e07d336 100644
--- a/common/env_flash.c
+++ b/common/env_flash.c
@@ -142,7 +142,7 @@ int saveenv(void)
 		goto done;
 
 	res = (char *)&env_new.data;
-	len = hexport_r(&env_htab, '\0', &res, ENV_SIZE, 0, NULL);
+	len = hexport_r(&env_htab, '\0', 0, &res, ENV_SIZE, 0, NULL);
 	if (len < 0) {
 		error("Cannot export environment: errno = %d\n", errno);
 		goto done;
@@ -275,7 +275,7 @@ int saveenv(void)
 		goto done;
 
 	res = (char *)&env_new.data;
-	len = hexport_r(&env_htab, '\0', &res, ENV_SIZE, 0, NULL);
+	len = hexport_r(&env_htab, '\0', 0, &res, ENV_SIZE, 0, NULL);
 	if (len < 0) {
 		error("Cannot export environment: errno = %d\n", errno);
 		goto done;
diff --git a/common/env_mmc.c b/common/env_mmc.c
index a2ff90b..ce21671 100644
--- a/common/env_mmc.c
+++ b/common/env_mmc.c
@@ -130,7 +130,7 @@ int saveenv(void)
 	}
 
 	res = (char *)&env_new->data;
-	len = hexport_r(&env_htab, '\0', &res, ENV_SIZE, 0, NULL);
+	len = hexport_r(&env_htab, '\0', 0, &res, ENV_SIZE, 0, NULL);
 	if (len < 0) {
 		error("Cannot export environment: errno = %d\n", errno);
 		ret = 1;
diff --git a/common/env_nand.c b/common/env_nand.c
index 79e8033..22e72a2 100644
--- a/common/env_nand.c
+++ b/common/env_nand.c
@@ -186,7 +186,7 @@ int saveenv(void)
 		return 1;
 
 	res = (char *)&env_new.data;
-	len = hexport_r(&env_htab, '\0', &res, ENV_SIZE, 0, NULL);
+	len = hexport_r(&env_htab, '\0', 0, &res, ENV_SIZE, 0, NULL);
 	if (len < 0) {
 		error("Cannot export environment: errno = %d\n", errno);
 		return 1;
@@ -239,7 +239,7 @@ int saveenv(void)
 		return 1;
 
 	res = (char *)&env_new->data;
-	len = hexport_r(&env_htab, '\0', &res, ENV_SIZE, 0, NULL);
+	len = hexport_r(&env_htab, '\0', 0, &res, ENV_SIZE, 0, NULL);
 	if (len < 0) {
 		error("Cannot export environment: errno = %d\n", errno);
 		return 1;
diff --git a/common/env_nvram.c b/common/env_nvram.c
index 6483db3..eab0e7b 100644
--- a/common/env_nvram.c
+++ b/common/env_nvram.c
@@ -90,7 +90,7 @@ int saveenv(void)
 	int	rcode = 0;
 
 	res = (char *)&env_new.data;
-	len = hexport_r(&env_htab, '\0', &res, ENV_SIZE, 0, NULL);
+	len = hexport_r(&env_htab, '\0', 0, &res, ENV_SIZE, 0, NULL);
 	if (len < 0) {
 		error("Cannot export environment: errno = %d\n", errno);
 		return 1;
diff --git a/common/env_onenand.c b/common/env_onenand.c
index da35071..faa903d 100644
--- a/common/env_onenand.c
+++ b/common/env_onenand.c
@@ -95,7 +95,7 @@ int saveenv(void)
 	};
 
 	res = (char *)&env_new.data;
-	len = hexport_r(&env_htab, '\0', &res, ENV_SIZE, 0, NULL);
+	len = hexport_r(&env_htab, '\0', 0, &res, ENV_SIZE, 0, NULL);
 	if (len < 0) {
 		error("Cannot export environment: errno = %d\n", errno);
 		return 1;
diff --git a/common/env_sf.c b/common/env_sf.c
index bbd472f..d9e9085 100644
--- a/common/env_sf.c
+++ b/common/env_sf.c
@@ -79,7 +79,7 @@ int saveenv(void)
 	}
 
 	res = (char *)&env_new.data;
-	len = hexport_r(&env_htab, '\0', &res, ENV_SIZE, 0, NULL);
+	len = hexport_r(&env_htab, '\0', 0, &res, ENV_SIZE, 0, NULL);
 	if (len < 0) {
 		error("Cannot export environment: errno = %d\n", errno);
 		return 1;
@@ -277,7 +277,7 @@ int saveenv(void)
 	}
 
 	res = (char *)&env_new.data;
-	len = hexport_r(&env_htab, '\0', &res, ENV_SIZE, 0, NULL);
+	len = hexport_r(&env_htab, '\0', 0, &res, ENV_SIZE, 0, NULL);
 	if (len < 0) {
 		error("Cannot export environment: errno = %d\n", errno);
 		goto done;
diff --git a/include/search.h b/include/search.h
index fa00ea1..1e48deb 100644
--- a/include/search.h
+++ b/include/search.h
@@ -107,7 +107,7 @@ extern int hdelete_r(const char *__key, struct hsearch_data *__htab,
 		     int __flag);
 
 extern ssize_t hexport_r(struct hsearch_data *__htab,
-		     const char __sep, char **__resp, size_t __size,
+		     const char __sep, int __flag, char **__resp, size_t __size,
 		     int argc, char * const argv[]);
 
 /*
@@ -120,9 +120,10 @@ extern int himport_r(struct hsearch_data *__htab,
 		     const char *__env, size_t __size, const char __sep,
 		     int __flag, int nvars, char * const vars[]);
 
-/* Flags for himport_r(), hdelete_r(), and hsearch_r() */
+/* Flags for himport_r(), hexport_r(), hdelete_r(), and hsearch_r() */
 #define H_NOCLEAR	(1 << 0) /* do not clear hash table before importing */
 #define H_FORCE		(1 << 1) /* overwrite read-only/write-once variables */
 #define H_INTERACTIVE	(1 << 2) /* indicate that an import is user directed */
+#define H_HIDE_DOT	(1 << 3) /* don't print env vars that begin with '.' */
 
 #endif /* search.h */
diff --git a/lib/hashtable.c b/lib/hashtable.c
index 6861a42..7c6b96c 100644
--- a/lib/hashtable.c
+++ b/lib/hashtable.c
@@ -522,7 +522,7 @@ static int cmpkey(const void *p1, const void *p2)
 	return (strcmp(e1->key, e2->key));
 }
 
-ssize_t hexport_r(struct hsearch_data *htab, const char sep,
+ssize_t hexport_r(struct hsearch_data *htab, const char sep, int flag,
 		 char **resp, size_t size,
 		 int argc, char * const argv[])
 {
@@ -559,6 +559,9 @@ ssize_t hexport_r(struct hsearch_data *htab, const char sep,
 			if ((argc > 0) && (found == 0))
 				continue;
 
+			if ((flag & H_HIDE_DOT) && ep->key[0] == '.')
+				continue;
+
 			list[n++] = ep;
 
 			totlen += strlen(ep->key) + 2;
-- 
1.7.11.5

^ permalink raw reply related	[flat|nested] 124+ messages in thread

* [U-Boot] [PATCH v4 07/20] env: Add support for callbacks to environment vars
  2012-12-05  1:52                                         ` [U-Boot] [PATCH v4 0/20] " Joe Hershberger
                                                             ` (5 preceding siblings ...)
  2012-12-05  1:52                                           ` [U-Boot] [PATCH v4 06/20] env: Hide '.' variables in env print by default Joe Hershberger
@ 2012-12-05  1:52                                           ` Joe Hershberger
  2012-12-05  2:34                                             ` Graeme Russ
  2012-12-05  1:52                                           ` [U-Boot] [PATCH v4 08/20] env: Add a command to view callbacks Joe Hershberger
                                                             ` (14 subsequent siblings)
  21 siblings, 1 reply; 124+ messages in thread
From: Joe Hershberger @ 2012-12-05  1:52 UTC (permalink / raw)
  To: u-boot

Add support for per-variable callbacks to the "hashtable" functions.

Signed-off-by: Joe Hershberger <joe.hershberger@ni.com>
---
Changes in v4: None
Changes in v3:
- Use Marek's linker lists instead of implementing it directly
- Rebase onto latest master
- Add flags parameter to callbacks
- Implement reverse search in env_attr_lookup()
- Fix space skipping in env_attr_lookup()
- All errors coming back from hsearch_r() are no longer fatal.  Don't
abort import on failed ENTER action.
- Removed checkpatch.pl warning

Changes in v2:
- Added much-needed documentation
- Factored out prevch and nextch in env_attr_lookup()

 README                 |  30 +++++++
 common/Makefile        |   4 +
 common/env_attr.c      | 222 +++++++++++++++++++++++++++++++++++++++++++++++++
 common/env_callback.c  | 132 +++++++++++++++++++++++++++++
 include/env_attr.h     |  55 ++++++++++++
 include/env_callback.h |  62 ++++++++++++++
 include/env_default.h  |   5 ++
 include/environment.h  |   2 +
 include/search.h       |   5 ++
 lib/hashtable.c        |  67 ++++++++++++++-
 10 files changed, 580 insertions(+), 4 deletions(-)
 create mode 100644 common/env_attr.c
 create mode 100644 common/env_callback.c
 create mode 100644 include/env_attr.h
 create mode 100644 include/env_callback.h

diff --git a/README b/README
index ed7d270..6b1698c 100644
--- a/README
+++ b/README
@@ -4168,6 +4168,36 @@ Please note that changes to some configuration parameters may take
 only effect after the next boot (yes, that's just like Windoze :-).
 
 
+Callback functions for environment variables:
+---------------------------------------------
+
+For some environment variables, the behavior of u-boot needs to change
+when their values are changed.  This functionailty allows functions to
+be associated with arbitrary variables.  On creation, overwrite, or
+deletion, the callback will provide the opportunity for some side
+effect to happen or for the change to be rejected.
+
+The callbacks are named and associated with a function using the
+U_BOOT_ENV_CALLBACK macro in your board or driver code.
+
+These callbacks are associated with variables in one of two ways.  The
+static list can be added to by defining CONFIG_ENV_CALLBACK_LIST_STATIC
+in the board configuration to a string that defines a list of
+associations.  The list must be in the following format:
+
+	entry = variable_name[:callback_name]
+	list = entry[,list]
+
+If the callback name is not specified, then the callback is deleted.
+Spaces are also allowed anywhere in the list.
+
+Callbacks can also be associated by defining the ".callbacks" variable
+with the same list format above.  Any association in ".callbacks" will
+override any association in the static list. You can define
+CONFIG_ENV_CALLBACK_LIST_DEFAULT to a list (string) to define the
+".callbacks" envirnoment variable in the default or embedded environment.
+
+
 Command Line Parsing:
 =====================
 
diff --git a/common/Makefile b/common/Makefile
index 9e43322..af6e8f9 100644
--- a/common/Makefile
+++ b/common/Makefile
@@ -43,6 +43,8 @@ COBJS-y += cmd_nvedit.o
 COBJS-y += cmd_version.o
 
 # environment
+COBJS-y += env_attr.o
+COBJS-y += env_callback.o
 COBJS-y += env_common.o
 COBJS-$(CONFIG_ENV_IS_IN_DATAFLASH) += env_dataflash.o
 COBJS-$(CONFIG_ENV_IS_IN_EEPROM) += env_eeprom.o
@@ -197,6 +199,8 @@ endif
 ifdef CONFIG_SPL_BUILD
 COBJS-$(CONFIG_SPL_YMODEM_SUPPORT) += xyzModem.o
 COBJS-$(CONFIG_SPL_NET_SUPPORT) += cmd_nvedit.o
+COBJS-$(CONFIG_SPL_NET_SUPPORT) += env_attr.o
+COBJS-$(CONFIG_SPL_NET_SUPPORT) += env_callback.o
 COBJS-$(CONFIG_SPL_NET_SUPPORT) += env_common.o
 COBJS-$(CONFIG_SPL_NET_SUPPORT) += env_nowhere.o
 COBJS-$(CONFIG_SPL_NET_SUPPORT) += miiphyutil.o
diff --git a/common/env_attr.c b/common/env_attr.c
new file mode 100644
index 0000000..7d330a5
--- /dev/null
+++ b/common/env_attr.c
@@ -0,0 +1,222 @@
+/*
+ * (C) Copyright 2012
+ * Joe Hershberger, National Instruments, joe.hershberger at 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
+ */
+
+#include <common.h>
+#include <env_attr.h>
+#include <errno.h>
+#include <linux/string.h>
+#include <malloc.h>
+
+/*
+ * Iterate through the whole list calling the callback for each found element.
+ * "attr_list" takes the form:
+ *	attributes = [^,:\s]*
+ *	entry = name[:attributes]
+ *	list = entry[,list]
+ */
+int env_attr_walk(const char *attr_list,
+	int (*callback)(const char *name, const char *attributes))
+{
+	const char *entry, *entry_end;
+	char *name, *attributes;
+
+	if (!attr_list)
+		/* list not found */
+		return 1;
+
+	entry = attr_list;
+	do {
+		char *entry_cpy = NULL;
+
+		entry_end = strchr(entry, ENV_ATTR_LIST_DELIM);
+		/* check if this is the last entry in the list */
+		if (entry_end == NULL) {
+			int entry_len = strlen(entry);
+
+			if (entry_len) {
+				/*
+				 * allocate memory to copy the entry into since
+				 * we will need to inject '\0' chars and squash
+				 * white-space before calling the callback
+				 */
+				entry_cpy = malloc(entry_len + 1);
+				if (entry_cpy)
+					/* copy the rest of the list */
+					strcpy(entry_cpy, entry);
+				else
+					return -ENOMEM;
+			}
+		} else {
+			int entry_len = entry_end - entry;
+
+			if (entry_len) {
+				/*
+				 * allocate memory to copy the entry into since
+				 * we will need to inject '\0' chars and squash
+				 * white-space before calling the callback
+				 */
+				entry_cpy = malloc(entry_len + 1);
+				if (entry_cpy) {
+					/* copy just this entry and null term */
+					strncpy(entry_cpy, entry, entry_len);
+					entry_cpy[entry_len] = '\0';
+				} else
+					return -ENOMEM;
+			}
+		}
+
+		/* check if there is anything to process (e.g. not ",,,") */
+		if (entry_cpy != NULL) {
+			attributes = strchr(entry_cpy, ENV_ATTR_SEP);
+			/* check if there is a ':' */
+			if (attributes != NULL) {
+				/* replace the ':' with '\0' to term name */
+				*attributes++ = '\0';
+				/* remove white-space from attributes */
+				attributes = strim(attributes);
+			}
+			/* remove white-space from name */
+			name = strim(entry_cpy);
+
+			/* only call the callback if there is a name */
+			if (strlen(name) != 0) {
+				int retval = 0;
+
+				retval = callback(name, attributes);
+				if (retval) {
+					free(entry_cpy);
+					return retval;
+				}
+			}
+		}
+
+		free(entry_cpy);
+		entry = entry_end + 1;
+	} while (entry_end != NULL);
+
+	return 0;
+}
+
+/*
+ * Search for the last matching string in another string with the option to
+ * start looking at a certain point (i.e. ignore anything beyond that point).
+ */
+static char *reverse_strstr(const char *searched, const char *search_for,
+	const char *searched_start)
+{
+	char *result = NULL;
+
+	if (*search_for == '\0')
+		return (char *)searched;
+
+	for (;;) {
+		char *match = strstr(searched, search_for);
+
+		/*
+		 * Stop looking if no new match is found or looking past the
+		 * searched_start pointer
+		 */
+		if (match == NULL || (searched_start != NULL &&
+		    match + strlen(search_for) > searched_start))
+			break;
+
+		result = match;
+		searched = match + 1;
+	}
+
+	return result;
+}
+
+/*
+ * Retrieve the attributes string associated with a single name in the list
+ * There is no protection on attributes being too small for the value
+ */
+int env_attr_lookup(const char *attr_list, const char *name, char *attributes)
+{
+	const char *entry = NULL;
+
+	if (!attributes)
+		/* bad parameter */
+		return -1;
+	if (!attr_list)
+		/* list not found */
+		return 1;
+
+	entry = reverse_strstr(attr_list, name, NULL);
+	while (entry != NULL) {
+		const char *prevch = entry - 1;
+		const char *nextch = entry + strlen(name);
+
+		/* Skip spaces */
+		while (*prevch == ' ')
+			prevch--;
+		while (*nextch == ' ')
+			nextch++;
+
+		/* check for an exact match */
+		if ((entry == attr_list ||
+		     *prevch == ENV_ATTR_LIST_DELIM) &&
+		    (*nextch == ENV_ATTR_SEP ||
+		     *nextch == ENV_ATTR_LIST_DELIM ||
+		     *nextch == '\0'))
+			break;
+
+		entry = reverse_strstr(attr_list, name, entry);
+	}
+	if (entry != NULL) {
+		int len;
+
+		/* skip the name */
+		entry += strlen(name);
+		/* skip spaces */
+		while (*entry == ' ')
+			entry++;
+		if (*entry != ENV_ATTR_SEP)
+			len = 0;
+		else {
+			const char *delim;
+			static const char delims[] = {
+				ENV_ATTR_LIST_DELIM, ' ', '\0'};
+
+			/* skip the attr sep */
+			entry += 1;
+			/* skip spaces */
+			while (*entry == ' ')
+				entry++;
+
+			delim = strpbrk(entry, delims);
+			if (delim == NULL)
+				len = strlen(entry);
+			else
+				len = delim - entry;
+			memcpy(attributes, entry, len);
+		}
+		attributes[len] = '\0';
+
+		/* success */
+		return 0;
+	}
+
+	/* not found in list */
+	return 2;
+}
diff --git a/common/env_callback.c b/common/env_callback.c
new file mode 100644
index 0000000..b3989c6
--- /dev/null
+++ b/common/env_callback.c
@@ -0,0 +1,132 @@
+/*
+ * (C) Copyright 2012
+ * Joe Hershberger, National Instruments, joe.hershberger at 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
+ */
+
+#include <common.h>
+#include <environment.h>
+
+/*
+ * Look up a callback function pointer by name
+ */
+struct env_clbk_tbl *find_env_callback(const char *name)
+{
+	struct env_clbk_tbl *clbkp;
+	int i;
+	int num_callbacks = ll_entry_count(struct env_clbk_tbl, env_clbk);
+
+	if (name == NULL)
+		return NULL;
+
+	/* look up the callback in the linker-list */
+	for (i = 0, clbkp = ll_entry_start(struct env_clbk_tbl, env_clbk);
+	     i < num_callbacks;
+	     i++, clbkp++) {
+		if (strcmp(name, clbkp->name) == 0)
+			return clbkp;
+	}
+
+	return NULL;
+}
+
+/*
+ * Look for a possible callback for a newly added variable
+ * This is called specifically when the variable did not exist in the hash
+ * previously, so the blanket update did not find this variable.
+ */
+void env_callback_init(ENTRY *var_entry)
+{
+	const char *var_name = var_entry->key;
+	const char *callback_list = getenv(ENV_CALLBACK_VAR);
+	char callback_name[256] = "";
+	struct env_clbk_tbl *clbkp;
+	int ret = 1;
+
+	/* look in the ".callbacks" var for a reference to this variable */
+	if (callback_list != NULL)
+		ret = env_attr_lookup(callback_list, var_name, callback_name);
+
+	/* only if not found there, look in the static list */
+	if (ret)
+		ret = env_attr_lookup(ENV_CALLBACK_LIST_STATIC, var_name,
+			callback_name);
+
+	/* if an association was found, set the callback pointer */
+	if (!ret && strlen(callback_name)) {
+		clbkp = find_env_callback(callback_name);
+		if (clbkp != NULL)
+			var_entry->callback = clbkp->callback;
+	}
+}
+
+/*
+ * Called on each existing env var prior to the blanket update since removing
+ * a callback association should remove its callback.
+ */
+static int clear_callback(ENTRY *entry)
+{
+	entry->callback = NULL;
+
+	return 0;
+}
+
+/*
+ * Call for each element in the list that associates variables to callbacks
+ */
+static int set_callback(const char *name, const char *value)
+{
+	ENTRY e, *ep;
+	struct env_clbk_tbl *clbkp;
+
+	e.key	= name;
+	e.data	= NULL;
+	hsearch_r(e, FIND, &ep, &env_htab, 0);
+
+	/* does the env variable actually exist? */
+	if (ep != NULL) {
+		/* the assocaition delares no callback, so remove the pointer */
+		if (value == NULL || strlen(value) == 0)
+			ep->callback = NULL;
+		else {
+			/* assign the requested callback */
+			clbkp = find_env_callback(value);
+			if (clbkp != NULL)
+				ep->callback = clbkp->callback;
+		}
+	}
+
+	return 0;
+}
+
+static int on_callbacks(const char *name, const char *value, enum env_op op,
+	int flags)
+{
+	/* remove all callbacks */
+	hwalk_r(&env_htab, clear_callback);
+
+	/* configure any static callback bindings */
+	env_attr_walk(ENV_CALLBACK_LIST_STATIC, set_callback);
+	/* configure any dynamic callback bindings */
+	env_attr_walk(value, set_callback);
+
+	return 0;
+}
+U_BOOT_ENV_CALLBACK(callbacks, on_callbacks);
diff --git a/include/env_attr.h b/include/env_attr.h
new file mode 100644
index 0000000..6ef114f
--- /dev/null
+++ b/include/env_attr.h
@@ -0,0 +1,55 @@
+/*
+ * (C) Copyright 2012
+ * Joe Hershberger, National Instruments, joe.hershberger at 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
+ */
+
+#ifndef __ENV_ATTR_H__
+#define __ENV_ATTR_H__
+
+#define ENV_ATTR_LIST_DELIM	','
+#define ENV_ATTR_SEP		':'
+
+/*
+ * env_attr_walk takes as input an "attr_list" that takes the form:
+ *	attributes = [^,:\s]*
+ *	entry = name[:attributes]
+ *	list = entry[,list]
+ * It will call the "callback" function with the "name" and attribute as "value"
+ * The callback may return a non-0 to abort the list walk.
+ * This return value will be passed through to the caller.
+ * 0 is returned on success.
+ */
+extern int env_attr_walk(const char *attr_list,
+	int (*callback)(const char *name, const char *value));
+
+/*
+ * env_attr_lookup takes as input an "attr_list" with the same form as above.
+ * It also takes as input a "name" to look for.
+ * If the name is found in the list, it's value is copied into "attributes".
+ * There is no protection on attributes being too small for the value.
+ * It returns -1 if attributes is NULL, 1 if "name" is not found, 2 if
+ * "attr_list" is NULL.
+ * Returns 0 on success.
+ */
+extern int env_attr_lookup(const char *attr_list, const char *name,
+	char *attributes);
+
+#endif /* __ENV_ATTR_H__ */
diff --git a/include/env_callback.h b/include/env_callback.h
new file mode 100644
index 0000000..1a25e3f
--- /dev/null
+++ b/include/env_callback.h
@@ -0,0 +1,62 @@
+/*
+ * (C) Copyright 2012
+ * Joe Hershberger, National Instruments, joe.hershberger at 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
+ */
+
+#ifndef __ENV_CALLBACK_H__
+#define __ENV_CALLBACK_H__
+
+#include <linker_lists.h>
+#include <search.h>
+
+#define ENV_CALLBACK_VAR ".callbacks"
+
+/* Board configs can define additional static callback bindings */
+#ifndef CONFIG_ENV_CALLBACK_LIST_STATIC
+#define CONFIG_ENV_CALLBACK_LIST_STATIC
+#endif
+
+/*
+ * This list of callback bindings is static, but may be overridden by defining
+ * a new assogiation in the ".callbacks" environment variable.
+ */
+#define ENV_CALLBACK_LIST_STATIC ENV_CALLBACK_VAR ":callbacks," \
+	CONFIG_ENV_CALLBACK_LIST_STATIC
+
+struct env_clbk_tbl {
+	const char *name;		/* Callback name */
+	int (*callback)(const char *name, const char *value, enum env_op op,
+		int flags);
+};
+
+struct env_clbk_tbl *find_env_callback(const char *);
+void env_callback_init(ENTRY *var_entry);
+
+/*
+ * Define a callback that can be associated with variables.
+ * when associated through the ".callbacks" environment variable, the callback
+ * will be executed any time the variable is inserted, overwritten, or deleted.
+ */
+#define U_BOOT_ENV_CALLBACK(name, callback) \
+	ll_entry_declare(struct env_clbk_tbl, name, env_clbk, env_clbk) = \
+	{#name, callback}
+
+#endif /* __ENV_CALLBACK_H__ */
diff --git a/include/env_default.h b/include/env_default.h
index a1db73a..d05eba1 100644
--- a/include/env_default.h
+++ b/include/env_default.h
@@ -24,6 +24,8 @@
  * MA 02111-1307 USA
  */
 
+#include <env_callback.h>
+
 #ifdef DEFAULT_ENV_INSTANCE_EMBEDDED
 env_t environment __PPCENV__ = {
 	ENV_CRC,	/* CRC Sum */
@@ -36,6 +38,9 @@ static char default_environment[] = {
 #else
 const uchar default_environment[] = {
 #endif
+#ifdef	CONFIG_ENV_CALLBACK_LIST_DEFAULT
+	ENV_CALLBACK_VAR "=" CONFIG_ENV_CALLBACK_LIST_DEFAULT "\0"
+#endif
 #ifdef	CONFIG_BOOTARGS
 	"bootargs="	CONFIG_BOOTARGS			"\0"
 #endif
diff --git a/include/environment.h b/include/environment.h
index 4b19f32..6c30215 100644
--- a/include/environment.h
+++ b/include/environment.h
@@ -164,6 +164,8 @@ extern void env_reloc(void);
 
 #ifndef DO_DEPS_ONLY
 
+#include <env_attr.h>
+#include <env_callback.h>
 #include <search.h>
 
 extern struct hsearch_data env_htab;
diff --git a/include/search.h b/include/search.h
index 1e48deb..d68e24a 100644
--- a/include/search.h
+++ b/include/search.h
@@ -47,6 +47,8 @@ typedef enum {
 typedef struct entry {
 	const char *key;
 	char *data;
+	int (*callback)(const char *name, const char *value, enum env_op op,
+		int flags);
 } ENTRY;
 
 /* Opaque type for internal use.  */
@@ -120,6 +122,9 @@ extern int himport_r(struct hsearch_data *__htab,
 		     const char *__env, size_t __size, const char __sep,
 		     int __flag, int nvars, char * const vars[]);
 
+/* Walk the whole table calling the callback on each element */
+extern int hwalk_r(struct hsearch_data *__htab, int (*callback)(ENTRY *));
+
 /* Flags for himport_r(), hexport_r(), hdelete_r(), and hsearch_r() */
 #define H_NOCLEAR	(1 << 0) /* do not clear hash table before importing */
 #define H_FORCE		(1 << 1) /* overwrite read-only/write-once variables */
diff --git a/lib/hashtable.c b/lib/hashtable.c
index 7c6b96c..e922666 100644
--- a/lib/hashtable.c
+++ b/lib/hashtable.c
@@ -54,7 +54,8 @@
 #define	CONFIG_ENV_MAX_ENTRIES 512
 #endif
 
-#include "search.h"
+#include <env_callback.h>
+#include <search.h>
 
 /*
  * [Aho,Sethi,Ullman] Compilers: Principles, Techniques and Tools, 1986
@@ -274,6 +275,17 @@ static inline int _compare_and_overwrite_entry(ENTRY item, ACTION action,
 				return 0;
 			}
 
+			/* If there is a callback, call it */
+			if (htab->table[idx].entry.callback &&
+			    htab->table[idx].entry.callback(item.key,
+			    item.data, env_op_overwrite, flag)) {
+				debug("callback() rejected setting variable "
+					"%s, skipping it!\n", item.key);
+				__set_errno(EINVAL);
+				*retval = NULL;
+				return 0;
+			}
+
 			free(htab->table[idx].entry.data);
 			htab->table[idx].entry.data = strdup(item.data);
 			if (!htab->table[idx].entry.data) {
@@ -398,6 +410,9 @@ int hsearch_r(ENTRY item, ACTION action, ENTRY ** retval,
 
 		++htab->filled;
 
+		/* This is a new entry, so look up a possible callback */
+		env_callback_init(&htab->table[idx].entry);
+
 		/* check for permission */
 		if (htab->change_ok != NULL && htab->change_ok(
 		    &htab->table[idx].entry, item.data, env_op_create, flag)) {
@@ -409,6 +424,18 @@ int hsearch_r(ENTRY item, ACTION action, ENTRY ** retval,
 			return 0;
 		}
 
+		/* If there is a callback, call it */
+		if (htab->table[idx].entry.callback &&
+		    htab->table[idx].entry.callback(item.key, item.data,
+		    env_op_create, flag)) {
+			debug("callback() rejected setting variable "
+				"%s, skipping it!\n", item.key);
+			_hdelete(item.key, htab, &htab->table[idx].entry, idx);
+			__set_errno(EINVAL);
+			*retval = NULL;
+			return 0;
+		}
+
 		/* return new entry */
 		*retval = &htab->table[idx].entry;
 		return 1;
@@ -437,6 +464,7 @@ static void _hdelete(const char *key, struct hsearch_data *htab, ENTRY *ep,
 	debug("hdelete: DELETING key \"%s\"\n", key);
 	free((void *)ep->key);
 	free(ep->data);
+	ep->callback = NULL;
 	htab->table[idx].used = -1;
 
 	--htab->filled;
@@ -466,6 +494,15 @@ int hdelete_r(const char *key, struct hsearch_data *htab, int flag)
 		return 0;
 	}
 
+	/* If there is a callback, call it */
+	if (htab->table[idx].entry.callback &&
+	    htab->table[idx].entry.callback(key, NULL, env_op_delete, flag)) {
+		debug("callback() rejected deleting variable "
+			"%s, skipping it!\n", key);
+		__set_errno(EINVAL);
+		return 0;
+	}
+
 	_hdelete(key, htab, ep, idx);
 
 	return 1;
@@ -838,11 +875,9 @@ int himport_r(struct hsearch_data *htab,
 		e.data = value;
 
 		hsearch_r(e, ENTER, &rv, htab, flag);
-		if (rv == NULL) {
+		if (rv == NULL)
 			printf("himport_r: can't insert \"%s=%s\" into hash table\n",
 				name, value);
-			return 0;
-		}
 
 		debug("INSERT: table %p, filled %d/%d rv %p ==> name=\"%s\" value=\"%s\"\n",
 			htab, htab->filled, htab->size,
@@ -873,3 +908,27 @@ int himport_r(struct hsearch_data *htab,
 	debug("INSERT: done\n");
 	return 1;		/* everything OK */
 }
+
+/*
+ * hwalk_r()
+ */
+
+/*
+ * Walk all of the entries in the hash, calling the callback for each one.
+ * this allows some generic operation to be performed on each element.
+ */
+int hwalk_r(struct hsearch_data *htab, int (*callback)(ENTRY *))
+{
+	int i;
+	int retval;
+
+	for (i = 1; i <= htab->size; ++i) {
+		if (htab->table[i].used > 0) {
+			retval = callback(&htab->table[i].entry);
+			if (retval)
+				return retval;
+		}
+	}
+
+	return 0;
+}
-- 
1.7.11.5

^ permalink raw reply related	[flat|nested] 124+ messages in thread

* [U-Boot] [PATCH v4 08/20] env: Add a command to view callbacks
  2012-12-05  1:52                                         ` [U-Boot] [PATCH v4 0/20] " Joe Hershberger
                                                             ` (6 preceding siblings ...)
  2012-12-05  1:52                                           ` [U-Boot] [PATCH v4 07/20] env: Add support for callbacks to environment vars Joe Hershberger
@ 2012-12-05  1:52                                           ` Joe Hershberger
  2012-12-05  1:52                                           ` [U-Boot] [PATCH v4 09/20] env: Add a bootfile env handler Joe Hershberger
                                                             ` (13 subsequent siblings)
  21 siblings, 0 replies; 124+ messages in thread
From: Joe Hershberger @ 2012-12-05  1:52 UTC (permalink / raw)
  To: u-boot

The callbacks can be bound, but are otherwise invisible.  Add a command
to show what callbacks are available.

Signed-off-by: Joe Hershberger <joe.hershberger@ni.com>
---
Changes in v4: None
Changes in v3: None
Changes in v2: None

 README              |  1 +
 common/cmd_nvedit.c | 77 +++++++++++++++++++++++++++++++++++++++++++++++++++++
 2 files changed, 78 insertions(+)

diff --git a/README b/README
index 6b1698c..e8b7b8b 100644
--- a/README
+++ b/README
@@ -810,6 +810,7 @@ The following options need to be configured:
 		CONFIG_CMD_EDITENV	  edit env variable
 		CONFIG_CMD_EEPROM	* EEPROM read/write support
 		CONFIG_CMD_ELF		* bootelf, bootvx
+		CONFIG_CMD_ENV_CALLBACK	* display details about env callbacks
 		CONFIG_CMD_EXPORTENV	* export the environment
 		CONFIG_CMD_EXT2		* ext2 command support
 		CONFIG_CMD_EXT4		* ext4 command support
diff --git a/common/cmd_nvedit.c b/common/cmd_nvedit.c
index 022ad39..e097941 100644
--- a/common/cmd_nvedit.c
+++ b/common/cmd_nvedit.c
@@ -514,6 +514,77 @@ int do_env_ask(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
 }
 #endif
 
+#if defined(CONFIG_CMD_ENV_CALLBACK)
+static int print_static_binding(const char *var_name, const char *callback_name)
+{
+	printf("\t%-20s %-20s\n", var_name, callback_name);
+
+	return 0;
+}
+
+static int print_active_callback(ENTRY *entry)
+{
+	struct env_clbk_tbl *clbkp;
+	int i;
+	int num_callbacks;
+
+	if (entry->callback == NULL)
+		return 0;
+
+	/* look up the callback in the linker-list */
+	num_callbacks = ll_entry_count(struct env_clbk_tbl, env_clbk);
+	for (i = 0, clbkp = ll_entry_start(struct env_clbk_tbl, env_clbk);
+	     i < num_callbacks;
+	     i++, clbkp++) {
+		if (entry->callback == clbkp->callback)
+			break;
+	}
+
+	if (i == num_callbacks)
+		/* this should probably never happen, but just in case... */
+		printf("\t%-20s %p\n", entry->key, entry->callback);
+	else
+		printf("\t%-20s %-20s\n", entry->key, clbkp->name);
+
+	return 0;
+}
+
+/*
+ * Print the callbacks available and what they are bound to
+ */
+int do_env_callback(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
+{
+	struct env_clbk_tbl *clbkp;
+	int i;
+	int num_callbacks;
+
+	/* Print the available callbacks */
+	puts("Available callbacks:\n");
+	puts("\tCallback Name\n");
+	puts("\t-------------\n");
+	num_callbacks = ll_entry_count(struct env_clbk_tbl, env_clbk);
+	for (i = 0, clbkp = ll_entry_start(struct env_clbk_tbl, env_clbk);
+	     i < num_callbacks;
+	     i++, clbkp++)
+		printf("\t%s\n", clbkp->name);
+	puts("\n");
+
+	/* Print the static bindings that may exist */
+	puts("Static callback bindings:\n");
+	printf("\t%-20s %-20s\n", "Variable Name", "Callback Name");
+	printf("\t%-20s %-20s\n", "-------------", "-------------");
+	env_attr_walk(ENV_CALLBACK_LIST_STATIC, print_static_binding);
+	puts("\n");
+
+	/* walk through each variable and print the callback if it has one */
+	puts("Active callback bindings:\n");
+	printf("\t%-20s %-20s\n", "Variable Name", "Callback Name");
+	printf("\t%-20s %-20s\n", "-------------", "-------------");
+	hwalk_r(&env_htab, print_active_callback);
+	return 0;
+}
+#endif
+
 /*
  * Interactively edit an environment variable
  */
@@ -981,6 +1052,9 @@ static cmd_tbl_t cmd_env_sub[] = {
 #if defined(CONFIG_CMD_EDITENV)
 	U_BOOT_CMD_MKENT(edit, 2, 0, do_env_edit, "", ""),
 #endif
+#if defined(CONFIG_CMD_ENV_CALLBACK)
+	U_BOOT_CMD_MKENT(callback, 1, 0, do_env_callback, "", ""),
+#endif
 #if defined(CONFIG_CMD_EXPORTENV)
 	U_BOOT_CMD_MKENT(export, 4, 0, do_env_export, "", ""),
 #endif
@@ -1031,6 +1105,9 @@ static char env_help_text[] =
 #if defined(CONFIG_CMD_ASKENV)
 	"ask name [message] [size] - ask for environment variable\nenv "
 #endif
+#if defined(CONFIG_CMD_CALLBACKENV)
+	"callback [name] - print callbacks and their associated variables\nenv "
+#endif
 	"default [-f] -a - [forcibly] reset default environment\n"
 	"env default [-f] var [...] - [forcibly] reset variable(s) to their default values\n"
 #if defined(CONFIG_CMD_EDITENV)
-- 
1.7.11.5

^ permalink raw reply related	[flat|nested] 124+ messages in thread

* [U-Boot] [PATCH v4 09/20] env: Add a bootfile env handler
  2012-12-05  1:52                                         ` [U-Boot] [PATCH v4 0/20] " Joe Hershberger
                                                             ` (7 preceding siblings ...)
  2012-12-05  1:52                                           ` [U-Boot] [PATCH v4 08/20] env: Add a command to view callbacks Joe Hershberger
@ 2012-12-05  1:52                                           ` Joe Hershberger
  2012-12-05  1:52                                           ` [U-Boot] [PATCH v4 10/20] env: Add a baudrate " Joe Hershberger
                                                             ` (12 subsequent siblings)
  21 siblings, 0 replies; 124+ messages in thread
From: Joe Hershberger @ 2012-12-05  1:52 UTC (permalink / raw)
  To: u-boot

Remove the hard-coded bootfile handler and use a callback instead

Signed-off-by: Joe Hershberger <joe.hershberger@ni.com>
---
Changes in v4: None
Changes in v3: None
Changes in v2: None

 common/cmd_nvedit.c    |  9 ---------
 include/env_callback.h |  1 +
 net/net.c              | 17 +++++++++++++++++
 3 files changed, 18 insertions(+), 9 deletions(-)

diff --git a/common/cmd_nvedit.c b/common/cmd_nvedit.c
index e097941..760c040 100644
--- a/common/cmd_nvedit.c
+++ b/common/cmd_nvedit.c
@@ -50,9 +50,6 @@
 #include <serial.h>
 #include <linux/stddef.h>
 #include <asm/byteorder.h>
-#if defined(CONFIG_CMD_NET)
-#include <net.h>
-#endif
 
 DECLARE_GLOBAL_DATA_PTR;
 
@@ -328,12 +325,6 @@ int env_change_ok(const ENTRY *item, const char *newval, enum env_op op,
 		load_addr = simple_strtoul(newval, NULL, 16);
 		return 0;
 	}
-#if defined(CONFIG_CMD_NET)
-	else if (strcmp(name, "bootfile") == 0) {
-		copy_filename(BootFile, newval, sizeof(BootFile));
-		return 0;
-	}
-#endif
 	return 0;
 }
 
diff --git a/include/env_callback.h b/include/env_callback.h
index 1a25e3f..caf2cc4 100644
--- a/include/env_callback.h
+++ b/include/env_callback.h
@@ -39,6 +39,7 @@
  * a new assogiation in the ".callbacks" environment variable.
  */
 #define ENV_CALLBACK_LIST_STATIC ENV_CALLBACK_VAR ":callbacks," \
+	"bootfile:bootfile," \
 	CONFIG_ENV_CALLBACK_LIST_STATIC
 
 struct env_clbk_tbl {
diff --git a/net/net.c b/net/net.c
index da68a61..a40cde1 100644
--- a/net/net.c
+++ b/net/net.c
@@ -82,6 +82,7 @@
 
 #include <common.h>
 #include <command.h>
+#include <environment.h>
 #include <net.h>
 #if defined(CONFIG_STATUS_LED)
 #include <miiphy.h>
@@ -208,6 +209,22 @@ static int NetTryCount;
 
 /**********************************************************************/
 
+static int on_bootfile(const char *name, const char *value, enum env_op op,
+	int flags)
+{
+	switch (op) {
+	case env_op_create:
+	case env_op_overwrite:
+		copy_filename(BootFile, value, sizeof(BootFile));
+		break;
+	default:
+		break;
+	}
+
+	return 0;
+}
+U_BOOT_ENV_CALLBACK(bootfile, on_bootfile);
+
 /*
  * Check if autoload is enabled. If so, use either NFS or TFTP to download
  * the boot file.
-- 
1.7.11.5

^ permalink raw reply related	[flat|nested] 124+ messages in thread

* [U-Boot] [PATCH v4 10/20] env: Add a baudrate env handler
  2012-12-05  1:52                                         ` [U-Boot] [PATCH v4 0/20] " Joe Hershberger
                                                             ` (8 preceding siblings ...)
  2012-12-05  1:52                                           ` [U-Boot] [PATCH v4 09/20] env: Add a bootfile env handler Joe Hershberger
@ 2012-12-05  1:52                                           ` Joe Hershberger
  2012-12-05  1:52                                           ` [U-Boot] [PATCH v4 11/20] env: Add a loadaddr " Joe Hershberger
                                                             ` (11 subsequent siblings)
  21 siblings, 0 replies; 124+ messages in thread
From: Joe Hershberger @ 2012-12-05  1:52 UTC (permalink / raw)
  To: u-boot

Remove the hard-coded baudrate handler and use a callback instead

Signed-off-by: Joe Hershberger <joe.hershberger@ni.com>
---
Changes in v4: None
Changes in v3: None
Changes in v2: None

 common/cmd_nvedit.c     | 47 ---------------------------------
 drivers/serial/serial.c | 70 +++++++++++++++++++++++++++++++++++++++++++++++++
 include/env_callback.h  |  1 +
 3 files changed, 71 insertions(+), 47 deletions(-)

diff --git a/common/cmd_nvedit.c b/common/cmd_nvedit.c
index 760c040..e344fea 100644
--- a/common/cmd_nvedit.c
+++ b/common/cmd_nvedit.c
@@ -78,12 +78,6 @@ ulong save_addr;			/* Default Save Address */
 ulong save_size;			/* Default Save Size (in bytes) */
 
 /*
- * Table with supported baudrates (defined in config_xyz.h)
- */
-static const unsigned long baudrate_table[] = CONFIG_SYS_BAUDRATE_TABLE;
-#define	N_BAUDRATES (sizeof(baudrate_table) / sizeof(baudrate_table[0]))
-
-/*
  * This variable is incremented on each do_env_set(), so it can
  * be used via get_env_id() as an indication, if the environment
  * has changed or not. So it is possible to reread an environment
@@ -275,47 +269,6 @@ int env_change_ok(const ENTRY *item, const char *newval, enum env_op op,
 		}
 	}
 #endif
-	/*
-	 * When we change baudrate, or we are doing an env default -a
-	 * (which will erase all variables prior to calling this),
-	 * we want the baudrate to actually change - for real.
-	 */
-	if (op != env_op_create ||		/* variable exists */
-		(flag & H_NOCLEAR) == 0) {	/* or env is clear */
-		/*
-		 * Switch to new baudrate if new baudrate is supported
-		 */
-		if (strcmp(name, "baudrate") == 0) {
-			int baudrate = simple_strtoul(newval, NULL, 10);
-			int i;
-			for (i = 0; i < N_BAUDRATES; ++i) {
-				if (baudrate == baudrate_table[i])
-					break;
-			}
-			if (i == N_BAUDRATES) {
-				if ((flag & H_FORCE) == 0)
-					printf("## Baudrate %d bps not "
-						"supported\n", 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);
-			gd->baudrate = baudrate;
-#if defined(CONFIG_PPC) || defined(CONFIG_MCF52x2)
-			gd->bd->bi_baudrate = baudrate;
-#endif
-
-			serial_setbrg();
-			udelay(50000);
-			while (getc() != '\r')
-				;
-		}
-	}
 
 	/*
 	 * Some variables should be updated when the corresponding
diff --git a/drivers/serial/serial.c b/drivers/serial/serial.c
index f5f43a6..1f8955a 100644
--- a/drivers/serial/serial.c
+++ b/drivers/serial/serial.c
@@ -22,6 +22,7 @@
  */
 
 #include <common.h>
+#include <environment.h>
 #include <serial.h>
 #include <stdio_dev.h>
 #include <post.h>
@@ -32,6 +33,11 @@ DECLARE_GLOBAL_DATA_PTR;
 
 static struct serial_device *serial_devices;
 static struct serial_device *serial_current;
+/*
+ * Table with supported baudrates (defined in config_xyz.h)
+ */
+static const unsigned long baudrate_table[] = CONFIG_SYS_BAUDRATE_TABLE;
+#define	N_BAUDRATES (sizeof(baudrate_table) / sizeof(baudrate_table[0]))
 
 /**
  * serial_null() - Void registration routine of a serial driver
@@ -46,6 +52,70 @@ static void serial_null(void)
 }
 
 /**
+ * on_baudrate() - Update the actual baudrate when the env var changes
+ *
+ * This will check for a valid baudrate and only apply it if valid.
+ */
+static int on_baudrate(const char *name, const char *value, enum env_op op,
+	int flags)
+{
+	int i;
+	int baudrate;
+
+	switch (op) {
+	case env_op_create:
+	case env_op_overwrite:
+		/*
+		 * Switch to new baudrate if new baudrate is supported
+		 */
+		baudrate = simple_strtoul(value, NULL, 10);
+
+		/* Not actually changing */
+		if (gd->baudrate == baudrate)
+			return 0;
+
+		for (i = 0; i < N_BAUDRATES; ++i) {
+			if (baudrate == baudrate_table[i])
+				break;
+		}
+		if (i == N_BAUDRATES) {
+			if ((flags & H_FORCE) == 0)
+				printf("## Baudrate %d bps not supported\n",
+					baudrate);
+			return 1;
+		}
+		if ((flags & H_INTERACTIVE) != 0) {
+			printf("## Switch baudrate to %d"
+				" bps and press ENTER ...\n", baudrate);
+			udelay(50000);
+		}
+
+		gd->baudrate = baudrate;
+#if defined(CONFIG_PPC) || defined(CONFIG_MCF52x2)
+		gd->bd->bi_baudrate = baudrate;
+#endif
+
+		serial_setbrg();
+
+		udelay(50000);
+
+		if ((flags & H_INTERACTIVE) != 0)
+			while (1) {
+				if (getc() == '\r')
+					break;
+			}
+
+		return 0;
+	case env_op_delete:
+		printf("## Baudrate may not be deleted\n");
+		return 1;
+	default:
+		return 0;
+	}
+}
+U_BOOT_ENV_CALLBACK(baudrate, on_baudrate);
+
+/**
  * serial_initfunc() - Forward declare of driver registration routine
  * @name:	Name of the real driver registration routine.
  *
diff --git a/include/env_callback.h b/include/env_callback.h
index caf2cc4..c3e800a 100644
--- a/include/env_callback.h
+++ b/include/env_callback.h
@@ -39,6 +39,7 @@
  * a new assogiation in the ".callbacks" environment variable.
  */
 #define ENV_CALLBACK_LIST_STATIC ENV_CALLBACK_VAR ":callbacks," \
+	"baudrate:baudrate," \
 	"bootfile:bootfile," \
 	CONFIG_ENV_CALLBACK_LIST_STATIC
 
-- 
1.7.11.5

^ permalink raw reply related	[flat|nested] 124+ messages in thread

* [U-Boot] [PATCH v4 11/20] env: Add a loadaddr env handler
  2012-12-05  1:52                                         ` [U-Boot] [PATCH v4 0/20] " Joe Hershberger
                                                             ` (9 preceding siblings ...)
  2012-12-05  1:52                                           ` [U-Boot] [PATCH v4 10/20] env: Add a baudrate " Joe Hershberger
@ 2012-12-05  1:52                                           ` Joe Hershberger
  2012-12-05  1:52                                           ` [U-Boot] [PATCH v4 12/20] env: Add a console " Joe Hershberger
                                                             ` (10 subsequent siblings)
  21 siblings, 0 replies; 124+ messages in thread
From: Joe Hershberger @ 2012-12-05  1:52 UTC (permalink / raw)
  To: u-boot

Remove the hard-coded loadaddr handler and use a callback instead

Signed-off-by: Joe Hershberger <joe.hershberger@ni.com>
---
Changes in v4: None
Changes in v3: None
Changes in v2: None

 common/cmd_nvedit.c    | 12 ------------
 common/image.c         | 21 +++++++++++++++++++++
 include/env_callback.h |  1 +
 3 files changed, 22 insertions(+), 12 deletions(-)

diff --git a/common/cmd_nvedit.c b/common/cmd_nvedit.c
index e344fea..37a684b 100644
--- a/common/cmd_nvedit.c
+++ b/common/cmd_nvedit.c
@@ -73,10 +73,6 @@ SPI_FLASH|NVRAM|MMC|FAT|REMOTE} or CONFIG_ENV_IS_NOWHERE
  */
 #define	MAX_ENV_SIZE	(1 << 20)	/* 1 MiB */
 
-ulong load_addr = CONFIG_SYS_LOAD_ADDR;	/* Default Load Address */
-ulong save_addr;			/* Default Save Address */
-ulong save_size;			/* Default Save Size (in bytes) */
-
 /*
  * This variable is incremented on each do_env_set(), so it can
  * be used via get_env_id() as an indication, if the environment
@@ -270,14 +266,6 @@ int env_change_ok(const ENTRY *item, const char *newval, enum env_op op,
 	}
 #endif
 
-	/*
-	 * Some variables should be updated when the corresponding
-	 * entry in the environment is changed
-	 */
-	if (strcmp(name, "loadaddr") == 0) {
-		load_addr = simple_strtoul(newval, NULL, 16);
-		return 0;
-	}
 	return 0;
 }
 
diff --git a/common/image.c b/common/image.c
index 69e888c..95498e6 100644
--- a/common/image.c
+++ b/common/image.c
@@ -43,6 +43,7 @@
 #include <rtc.h>
 #endif
 
+#include <environment.h>
 #include <image.h>
 
 #if defined(CONFIG_FIT) || defined(CONFIG_OF_LIBFDT)
@@ -416,6 +417,26 @@ static const image_header_t *image_get_ramdisk(ulong rd_addr, uint8_t arch,
 /* Shared dual-format routines */
 /*****************************************************************************/
 #ifndef USE_HOSTCC
+ulong load_addr = CONFIG_SYS_LOAD_ADDR;	/* Default Load Address */
+ulong save_addr;			/* Default Save Address */
+ulong save_size;			/* Default Save Size (in bytes) */
+
+static int on_loadaddr(const char *name, const char *value, enum env_op op,
+	int flags)
+{
+	switch (op) {
+	case env_op_create:
+	case env_op_overwrite:
+		load_addr = simple_strtoul(value, NULL, 16);
+		break;
+	default:
+		break;
+	}
+
+	return 0;
+}
+U_BOOT_ENV_CALLBACK(loadaddr, on_loadaddr);
+
 ulong getenv_bootm_low(void)
 {
 	char *s = getenv("bootm_low");
diff --git a/include/env_callback.h b/include/env_callback.h
index c3e800a..309ff9b 100644
--- a/include/env_callback.h
+++ b/include/env_callback.h
@@ -41,6 +41,7 @@
 #define ENV_CALLBACK_LIST_STATIC ENV_CALLBACK_VAR ":callbacks," \
 	"baudrate:baudrate," \
 	"bootfile:bootfile," \
+	"loadaddr:loadaddr," \
 	CONFIG_ENV_CALLBACK_LIST_STATIC
 
 struct env_clbk_tbl {
-- 
1.7.11.5

^ permalink raw reply related	[flat|nested] 124+ messages in thread

* [U-Boot] [PATCH v4 12/20] env: Add a console env handler
  2012-12-05  1:52                                         ` [U-Boot] [PATCH v4 0/20] " Joe Hershberger
                                                             ` (10 preceding siblings ...)
  2012-12-05  1:52                                           ` [U-Boot] [PATCH v4 11/20] env: Add a loadaddr " Joe Hershberger
@ 2012-12-05  1:52                                           ` Joe Hershberger
  2012-12-05  1:52                                           ` [U-Boot] [PATCH v4 13/20] env: Add a silent " Joe Hershberger
                                                             ` (9 subsequent siblings)
  21 siblings, 0 replies; 124+ messages in thread
From: Joe Hershberger @ 2012-12-05  1:52 UTC (permalink / raw)
  To: u-boot

Remove the hard-coded console handler and use a callback instead

Signed-off-by: Joe Hershberger <joe.hershberger@ni.com>
---
Changes in v4: None
Changes in v3: None
Changes in v2: None

 common/cmd_nvedit.c    | 36 +++---------------------------------
 common/console.c       | 44 ++++++++++++++++++++++++++++++++++++++++++++
 include/env_callback.h |  1 +
 3 files changed, 48 insertions(+), 33 deletions(-)

diff --git a/common/cmd_nvedit.c b/common/cmd_nvedit.c
index 37a684b..71debe3 100644
--- a/common/cmd_nvedit.c
+++ b/common/cmd_nvedit.c
@@ -47,7 +47,6 @@
 #include <errno.h>
 #include <malloc.h>
 #include <watchdog.h>
-#include <serial.h>
 #include <linux/stddef.h>
 #include <asm/byteorder.h>
 
@@ -206,10 +205,9 @@ static int do_env_grep(cmd_tbl_t *cmdtp, int flag,
 int env_change_ok(const ENTRY *item, const char *newval, enum env_op op,
 	int flag)
 {
-	int   console = -1;
+#ifndef CONFIG_ENV_OVERWRITE
 	const char *name;
-#if !defined(CONFIG_ENV_OVERWRITE) && defined(CONFIG_OVERWRITE_ETHADDR_ONCE) \
-&& defined(CONFIG_ETHADDR)
+#if defined(CONFIG_OVERWRITE_ETHADDR_ONCE) && defined(CONFIG_ETHADDR)
 	const char *oldval = NULL;
 
 	if (op != env_op_create)
@@ -217,35 +215,7 @@ int env_change_ok(const ENTRY *item, const char *newval, enum env_op op,
 #endif
 
 	name = item->key;
-
-	/* Default value for NULL to protect string-manipulating functions */
-	newval = newval ? : "";
-
-	/* Check for console redirection */
-	if (strcmp(name, "stdin") == 0)
-		console = stdin;
-	else if (strcmp(name, "stdout") == 0)
-		console = stdout;
-	else if (strcmp(name, "stderr") == 0)
-		console = stderr;
-
-	if (console != -1 && (gd->flags & GD_FLG_DEVINIT) != 0) {
-		if ((newval == NULL) || (*newval == '\0')) {
-			/* We cannot delete stdin/stdout/stderr */
-			if ((flag & H_FORCE) == 0)
-				printf("Can't delete \"%s\"\n", name);
-			return 1;
-		}
-
-#ifdef CONFIG_CONSOLE_MUX
-		if (iomux_doenv(console, newval))
-			return 1;
-#else
-		/* Try assigning specified device */
-		if (console_assign(console, newval) < 0)
-			return 1;
-#endif /* CONFIG_CONSOLE_MUX */
-	}
+#endif
 
 #ifndef CONFIG_ENV_OVERWRITE
 	/*
diff --git a/common/console.c b/common/console.c
index 880acd9..549d379 100644
--- a/common/console.c
+++ b/common/console.c
@@ -24,11 +24,55 @@
 #include <common.h>
 #include <stdarg.h>
 #include <malloc.h>
+#include <serial.h>
 #include <stdio_dev.h>
 #include <exports.h>
+#include <environment.h>
 
 DECLARE_GLOBAL_DATA_PTR;
 
+static int on_console(const char *name, const char *value, enum env_op op,
+	int flags)
+{
+	int console = -1;
+
+	/* Check for console redirection */
+	if (strcmp(name, "stdin") == 0)
+		console = stdin;
+	else if (strcmp(name, "stdout") == 0)
+		console = stdout;
+	else if (strcmp(name, "stderr") == 0)
+		console = stderr;
+
+	/* if not actually setting a console variable, we don't care */
+	if (console == -1 || (gd->flags & GD_FLG_DEVINIT) == 0)
+		return 0;
+
+	switch (op) {
+	case env_op_create:
+	case env_op_overwrite:
+
+#ifdef CONFIG_CONSOLE_MUX
+		if (iomux_doenv(console, value))
+			return 1;
+#else
+		/* Try assigning specified device */
+		if (console_assign(console, value) < 0)
+			return 1;
+#endif /* CONFIG_CONSOLE_MUX */
+		return 0;
+
+	case env_op_delete:
+		if ((flags & H_FORCE) == 0)
+			printf("Can't delete \"%s\"\n", name);
+		return 1;
+
+	default:
+		return 0;
+	}
+}
+U_BOOT_ENV_CALLBACK(console, on_console);
+
 #ifdef CONFIG_SYS_CONSOLE_IS_IN_ENV
 /*
  * if overwrite_console returns 1, the stdin, stderr and stdout
diff --git a/include/env_callback.h b/include/env_callback.h
index 309ff9b..a614744 100644
--- a/include/env_callback.h
+++ b/include/env_callback.h
@@ -42,6 +42,7 @@
 	"baudrate:baudrate," \
 	"bootfile:bootfile," \
 	"loadaddr:loadaddr," \
+	"stdin:console,stdout:console,stderr:console," \
 	CONFIG_ENV_CALLBACK_LIST_STATIC
 
 struct env_clbk_tbl {
-- 
1.7.11.5

^ permalink raw reply related	[flat|nested] 124+ messages in thread

* [U-Boot] [PATCH v4 13/20] env: Add a silent env handler
  2012-12-05  1:52                                         ` [U-Boot] [PATCH v4 0/20] " Joe Hershberger
                                                             ` (11 preceding siblings ...)
  2012-12-05  1:52                                           ` [U-Boot] [PATCH v4 12/20] env: Add a console " Joe Hershberger
@ 2012-12-05  1:52                                           ` Joe Hershberger
  2012-12-05  1:52                                           ` [U-Boot] [PATCH v4 14/20] env: Add environment variable flags Joe Hershberger
                                                             ` (8 subsequent siblings)
  21 siblings, 0 replies; 124+ messages in thread
From: Joe Hershberger @ 2012-12-05  1:52 UTC (permalink / raw)
  To: u-boot

The silent variable now updates the global data flag anytime it is
changed as well as after the env relocation (in case its value is
different from the default env in such cases as NAND env)

Signed-off-by: Joe Hershberger <joe.hershberger@ni.com>
---
Changes in v4: None
Changes in v3: None
Changes in v2: None

 common/console.c       | 23 +++++++++++++++++++++++
 doc/README.silent      | 14 ++++++++++----
 include/env_callback.h |  7 +++++++
 3 files changed, 40 insertions(+), 4 deletions(-)

diff --git a/common/console.c b/common/console.c
index 549d379..3322bcc 100644
--- a/common/console.c
+++ b/common/console.c
@@ -73,6 +73,29 @@ static int on_console(const char *name, const char *value, enum env_op op,
 }
 U_BOOT_ENV_CALLBACK(console, on_console);
 
+#ifdef CONFIG_SILENT_CONSOLE
+static int on_silent(const char *name, const char *value, enum env_op op,
+	int flags)
+{
+#ifndef CONFIG_SILENT_CONSOLE_UPDATE_ON_SET
+	if (flags & H_INTERACTIVE)
+		return 0;
+#endif
+#ifndef CONFIG_SILENT_CONSOLE_UPDATE_ON_RELOC
+	if ((flags & H_INTERACTIVE) == 0)
+		return 0;
+#endif
+
+	if (value != NULL)
+		gd->flags |= GD_FLG_SILENT;
+	else
+		gd->flags &= ~GD_FLG_SILENT;
+
+	return 0;
+}
+U_BOOT_ENV_CALLBACK(silent, on_silent);
+#endif
+
 #ifdef CONFIG_SYS_CONSOLE_IS_IN_ENV
 /*
  * if overwrite_console returns 1, the stdin, stderr and stdout
diff --git a/doc/README.silent b/doc/README.silent
index a26e3df..70202ce 100644
--- a/doc/README.silent
+++ b/doc/README.silent
@@ -1,9 +1,15 @@
 The config option CONFIG_SILENT_CONSOLE can be used to quiet messages
 on the console.  If the option has been enabled, the output can be
-silenced by setting the environment variable "silent".  The variable
-is latched into the global data at an early stage in the boot process
-so deleting it with "setenv" will not take effect until the system is
-restarted.
+silenced by setting the environment variable "silent".
+
+- CONFIG_SILENT_CONSOLE_UPDATE_ON_SET
+	When the "silent" variable is changed with env set, the change
+	will take effect immediately.
+
+- CONFIG_SILENT_CONSOLE_UPDATE_ON_RELOC
+	Some environments are not available until relocation (e.g. NAND)
+	so this will make the value in the flash env take effect at
+	relocation.
 
 The following actions are taken if "silent" is set at boot time:
 
diff --git a/include/env_callback.h b/include/env_callback.h
index a614744..d0e0e00 100644
--- a/include/env_callback.h
+++ b/include/env_callback.h
@@ -34,6 +34,12 @@
 #define CONFIG_ENV_CALLBACK_LIST_STATIC
 #endif
 
+#ifdef CONFIG_SILENT_CONSOLE
+#define SILENT_CALLBACK "silent:silent,"
+#else
+#define SILENT_CALLBACK
+#endif
+
 /*
  * This list of callback bindings is static, but may be overridden by defining
  * a new assogiation in the ".callbacks" environment variable.
@@ -42,6 +48,7 @@
 	"baudrate:baudrate," \
 	"bootfile:bootfile," \
 	"loadaddr:loadaddr," \
+	SILENT_CALLBACK \
 	"stdin:console,stdout:console,stderr:console," \
 	CONFIG_ENV_CALLBACK_LIST_STATIC
 
-- 
1.7.11.5

^ permalink raw reply related	[flat|nested] 124+ messages in thread

* [U-Boot] [PATCH v4 14/20] env: Add environment variable flags
  2012-12-05  1:52                                         ` [U-Boot] [PATCH v4 0/20] " Joe Hershberger
                                                             ` (12 preceding siblings ...)
  2012-12-05  1:52                                           ` [U-Boot] [PATCH v4 13/20] env: Add a silent " Joe Hershberger
@ 2012-12-05  1:52                                           ` Joe Hershberger
  2012-12-05  1:52                                           ` [U-Boot] [PATCH v4 15/20] tools/env: Add environment variable flags support Joe Hershberger
                                                             ` (7 subsequent siblings)
  21 siblings, 0 replies; 124+ messages in thread
From: Joe Hershberger @ 2012-12-05  1:52 UTC (permalink / raw)
  To: u-boot

Currently just validates variable types as decimal, hexidecimal,
boolean, ip address, and mac address.

If the entry is not found in the env ".flags", then look in the static
one. This allows the env to override the static definitions, but prevents
the need to have every definition in the environment distracting you.

Signed-off-by: Joe Hershberger <joe.hershberger@ni.com>
---
Changes in v4: None
Changes in v3: None
Changes in v2: None

 README                 |  37 ++++++
 common/Makefile        |   2 +
 common/cmd_nvedit.c    |  50 +-------
 common/env_common.c    |   2 +-
 common/env_flags.c     | 314 +++++++++++++++++++++++++++++++++++++++++++++++++
 include/env_callback.h |   2 +
 include/env_default.h  |   3 +
 include/env_flags.h    |  76 ++++++++++++
 include/environment.h  |   9 +-
 include/search.h       |   1 +
 lib/hashtable.c        |   4 +
 11 files changed, 442 insertions(+), 58 deletions(-)
 create mode 100644 common/env_flags.c
 create mode 100644 include/env_flags.h

diff --git a/README b/README
index e8b7b8b..5705925 100644
--- a/README
+++ b/README
@@ -2168,6 +2168,11 @@ CBFS (Coreboot Filesystem) support
 		serial# is unaffected by this, i. e. it remains
 		read-only.]
 
+		The same can be accomplished in a more flexible way
+		for any variable by configuring the type of access
+		to allow for those variables in the ".flags" variable
+		or define CONFIG_ENV_FLAGS_LIST_STATIC.
+
 - Protected RAM:
 		CONFIG_PRAM
 
@@ -3068,6 +3073,38 @@ Configuration Settings:
 	cases. This setting can be used to tune behaviour; see
 	lib/hashtable.c for details.
 
+- CONFIG_ENV_FLAGS_LIST_DEFAULT
+- CONFIG_ENV_FLAGS_LIST_STATIC
+	Enable validation of the values given to enviroment variables when
+	calling env set.  Variables can be restricted to only decimal,
+	hexadecimal, or boolean.  If CONFIG_CMD_NET is also defined,
+	the variables can also be restricted to IP address or MAC address.
+
+	The format of the list is:
+		type_attribute = [s|d|x|b|i|m]
+		attributes = type_attribute
+		entry = variable_name[:attributes]
+		list = entry[,list]
+
+	The type attributes are:
+		s - String (default)
+		d - Decimal
+		x - Hexadecimal
+		b - Boolean ([1yYtT|0nNfF])
+		i - IP address
+		m - MAC address
+
+	- CONFIG_ENV_FLAGS_LIST_DEFAULT
+		Define this to a list (string) to define the ".flags"
+		envirnoment variable in the default or embedded environment.
+
+	- CONFIG_ENV_FLAGS_LIST_STATIC
+		Define this to a list (string) to define validation that
+		should be done if an entry is not found in the ".flags"
+		environment variable.  To override a setting in the static
+		list, simply add an entry for the same variable name to the
+		".flags" variable.
+
 The following definitions that deal with the placement and management
 of environment data (variable area); in general, we support the
 following configurations:
diff --git a/common/Makefile b/common/Makefile
index af6e8f9..ef2bd00 100644
--- a/common/Makefile
+++ b/common/Makefile
@@ -46,6 +46,7 @@ COBJS-y += cmd_version.o
 COBJS-y += env_attr.o
 COBJS-y += env_callback.o
 COBJS-y += env_common.o
+COBJS-y += env_flags.o
 COBJS-$(CONFIG_ENV_IS_IN_DATAFLASH) += env_dataflash.o
 COBJS-$(CONFIG_ENV_IS_IN_EEPROM) += env_eeprom.o
 XCOBJS-$(CONFIG_ENV_IS_EMBEDDED) += env_embedded.o
@@ -202,6 +203,7 @@ COBJS-$(CONFIG_SPL_NET_SUPPORT) += cmd_nvedit.o
 COBJS-$(CONFIG_SPL_NET_SUPPORT) += env_attr.o
 COBJS-$(CONFIG_SPL_NET_SUPPORT) += env_callback.o
 COBJS-$(CONFIG_SPL_NET_SUPPORT) += env_common.o
+COBJS-$(CONFIG_SPL_NET_SUPPORT) += env_flags.o
 COBJS-$(CONFIG_SPL_NET_SUPPORT) += env_nowhere.o
 COBJS-$(CONFIG_SPL_NET_SUPPORT) += miiphyutil.o
 endif
diff --git a/common/cmd_nvedit.c b/common/cmd_nvedit.c
index 71debe3..4b2b040 100644
--- a/common/cmd_nvedit.c
+++ b/common/cmd_nvedit.c
@@ -192,57 +192,9 @@ static int do_env_grep(cmd_tbl_t *cmdtp, int flag,
 #endif /* CONFIG_SPL_BUILD */
 
 /*
- * Perform 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 instead.
- * Also called as a callback function by himport_r().
- * Returns 0 in case of success, 1 in case of failure.
- * When (flag & H_FORCE) is set, do not print out any error message and force
- * overwriting of write-once variables.
- */
-
-int env_change_ok(const ENTRY *item, const char *newval, enum env_op op,
-	int flag)
-{
-#ifndef CONFIG_ENV_OVERWRITE
-	const char *name;
-#if defined(CONFIG_OVERWRITE_ETHADDR_ONCE) && defined(CONFIG_ETHADDR)
-	const char *oldval = NULL;
-
-	if (op != env_op_create)
-		oldval = item->data;
-#endif
-
-	name = item->key;
-#endif
-
-#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
-
-	return 0;
-}
-
-/*
  * Set a new environment variable,
  * or replace or delete an existing one.
-*/
+ */
 static int _do_env_set(int flag, int argc, char * const argv[])
 {
 	int   i, len;
diff --git a/common/env_common.c b/common/env_common.c
index a86f061..b711337 100644
--- a/common/env_common.c
+++ b/common/env_common.c
@@ -40,7 +40,7 @@ DECLARE_GLOBAL_DATA_PTR;
 #include <env_default.h>
 
 struct hsearch_data env_htab = {
-	.change_ok = env_change_ok,
+	.change_ok = env_flags_validate,
 };
 
 static uchar __env_get_char_spec(int index)
diff --git a/common/env_flags.c b/common/env_flags.c
new file mode 100644
index 0000000..2292569
--- /dev/null
+++ b/common/env_flags.c
@@ -0,0 +1,314 @@
+/*
+ * (C) Copyright 2012
+ * Joe Hershberger, National Instruments, joe.hershberger at 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
+ */
+
+#include <linux/string.h>
+#include <linux/ctype.h>
+
+#include <common.h>
+#include <environment.h>
+
+#ifdef CONFIG_CMD_NET
+#define ENV_FLAGS_NET_VARTYPE_REPS "im"
+#else
+#define ENV_FLAGS_NET_VARTYPE_REPS ""
+#endif
+
+static const char env_flags_vartype_rep[] = "sdxb" ENV_FLAGS_NET_VARTYPE_REPS;
+
+/*
+ * Parse the flags string from a .flags attribute list into the vartype enum.
+ */
+enum env_flags_vartype env_flags_parse_vartype(const char *flags)
+{
+	char *type = strchr(env_flags_vartype_rep,
+		flags[ENV_FLAGS_VARTYPE_LOC]);
+
+	if (type != NULL)
+		return (enum env_flags_vartype)
+			(type - &env_flags_vartype_rep[0]);
+
+	printf("## Warning: Unknown environment variable type '%c'\n",
+		flags[ENV_FLAGS_VARTYPE_LOC]);
+	return env_flags_vartype_string;
+}
+
+static inline int is_hex_prefix(const char *value)
+{
+	return value[0] == '0' && (value[1] == 'x' || value[1] == 'X');
+}
+
+static void skip_num(int hex, const char *value, const char **end,
+	int max_digits)
+{
+	int i;
+
+	if (hex && is_hex_prefix(value))
+		value += 2;
+
+	for (i = max_digits; i != 0; i--) {
+		if (hex && !isxdigit(*value))
+			break;
+		if (!hex && !isdigit(*value))
+			break;
+		value++;
+	}
+	if (end != NULL)
+		*end = value;
+}
+
+/*
+ * Based on the declared type enum, validate that the value string complies
+ * with that format
+ */
+static int _env_flags_validate_type(const char *value,
+	enum env_flags_vartype type)
+{
+	const char *end;
+#ifdef CONFIG_CMD_NET
+	const char *cur;
+	int i;
+#endif
+
+	switch (type) {
+	case env_flags_vartype_string:
+		break;
+	case env_flags_vartype_decimal:
+		skip_num(0, value, &end, -1);
+		if (*end != '\0')
+			return -1;
+		break;
+	case env_flags_vartype_hex:
+		skip_num(1, value, &end, -1);
+		if (*end != '\0')
+			return -1;
+		if (value + 2 == end && is_hex_prefix(value))
+			return -1;
+		break;
+	case env_flags_vartype_bool:
+		if (value[0] != '1' && value[0] != 'y' && value[0] != 't' &&
+		    value[0] != 'Y' && value[0] != 'T' &&
+		    value[0] != '0' && value[0] != 'n' && value[0] != 'f' &&
+		    value[0] != 'N' && value[0] != 'F')
+			return -1;
+		if (value[1] != '\0')
+			return -1;
+		break;
+#ifdef CONFIG_CMD_NET
+	case env_flags_vartype_ipaddr:
+		cur = value;
+		for (i = 0; i < 4; i++) {
+			skip_num(0, cur, &end, 3);
+			if (cur == end)
+				return -1;
+			if (i != 3 && *end != '.')
+				return -1;
+			if (i == 3 && *end != '\0')
+				return -1;
+			cur = end + 1;
+		}
+		break;
+	case env_flags_vartype_macaddr:
+		cur = value;
+		for (i = 0; i < 6; i++) {
+			skip_num(1, cur, &end, 2);
+			if (cur == end)
+				return -1;
+			if (cur + 2 == end && is_hex_prefix(cur))
+				return -1;
+			if (i != 5 && *end != ':')
+				return -1;
+			if (i == 5 && *end != '\0')
+				return -1;
+			cur = end + 1;
+		}
+		break;
+#endif
+	case env_flags_vartype_end:
+		return -1;
+	}
+
+	/* OK */
+	return 0;
+}
+
+/*
+ * Look for flags in a provided list and failing that the static list
+ */
+static inline int env_flags_lookup(const char *flags_list, const char *name,
+	char *flags)
+{
+	int ret = 1;
+
+	if (!flags)
+		/* bad parameter */
+		return -1;
+
+	/* try the env first */
+	if (flags_list)
+		ret = env_attr_lookup(flags_list, name, flags);
+
+	if (ret != 0)
+		/* if not found in the env, look in the static list */
+		ret = env_attr_lookup(ENV_FLAGS_LIST_STATIC, name, flags);
+
+	return ret;
+}
+
+/*
+ * Parse the flag charachters from the .flags attribute list into the binary
+ * form to be stored in the environment entry->flags field.
+ */
+static int env_parse_flags_to_bin(const char *flags)
+{
+	return env_flags_parse_vartype(flags) & ENV_FLAGS_VARTYPE_BIN_MASK;
+}
+
+/*
+ * Look for possible flags for a newly added variable
+ * This is called specifically when the variable did not exist in the hash
+ * previously, so the blanket update did not find this variable.
+ */
+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;
+
+	/* look in the ".flags" and static for a reference to this variable */
+	ret = env_flags_lookup(flags_list, var_name, flags);
+
+	/* if any flags were found, set the binary form to the entry */
+	if (!ret && strlen(flags))
+		var_entry->flags = env_parse_flags_to_bin(flags);
+}
+
+/*
+ * Called on each existing env var prior to the blanket update since removing
+ * a flag in the flag list should remove its flags.
+ */
+static int clear_flags(ENTRY *entry)
+{
+	entry->flags = 0;
+
+	return 0;
+}
+
+/*
+ * Call for each element in the list that defines flags for a variable
+ */
+static int set_flags(const char *name, const char *value)
+{
+	ENTRY e, *ep;
+
+	e.key	= name;
+	e.data	= NULL;
+	hsearch_r(e, FIND, &ep, &env_htab, 0);
+
+	/* does the env variable actually exist? */
+	if (ep != NULL) {
+		/* the flag list is empty, so clear the flags */
+		if (value == NULL || strlen(value) == 0)
+			ep->flags = 0;
+		else
+			/* assign the requested flags */
+			ep->flags = env_parse_flags_to_bin(value);
+	}
+
+	return 0;
+}
+
+static int on_flags(const char *name, const char *value, enum env_op op,
+	int flags)
+{
+	/* remove all flags */
+	hwalk_r(&env_htab, clear_flags);
+
+	/* configure any static flags */
+	env_attr_walk(ENV_FLAGS_LIST_STATIC, set_flags);
+	/* configure any dynamic flags */
+	env_attr_walk(value, set_flags);
+
+	return 0;
+}
+U_BOOT_ENV_CALLBACK(flags, on_flags);
+
+/*
+ * Perform consistency checking before creating, overwriting, or deleting an
+ * environment variable. Called as a callback function by hsearch_r() and
+ * hdelete_r(). Returns 0 in case of success, 1 in case of failure.
+ * When (flag & H_FORCE) is set, do not print out any error message and force
+ * overwriting of write-once variables.
+ */
+
+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;
+		type = (enum env_flags_vartype)
+			(ENV_FLAGS_VARTYPE_BIN_MASK & item->flags);
+		if (_env_flags_validate_type(newval, type) < 0) {
+			printf("## Error: flags type check failure for "
+				"\"%s\" <= \"%s\" (type: %c)\n",
+				name, newval, env_flags_vartype_rep[type]);
+			return -1;
+		}
+	}
+
+	return 0;
+}
diff --git a/include/env_callback.h b/include/env_callback.h
index d0e0e00..1d8bb0e 100644
--- a/include/env_callback.h
+++ b/include/env_callback.h
@@ -24,6 +24,7 @@
 #ifndef __ENV_CALLBACK_H__
 #define __ENV_CALLBACK_H__
 
+#include <env_flags.h>
 #include <linker_lists.h>
 #include <search.h>
 
@@ -45,6 +46,7 @@
  * a new assogiation in the ".callbacks" environment variable.
  */
 #define ENV_CALLBACK_LIST_STATIC ENV_CALLBACK_VAR ":callbacks," \
+	ENV_FLAGS_VAR ":flags," \
 	"baudrate:baudrate," \
 	"bootfile:bootfile," \
 	"loadaddr:loadaddr," \
diff --git a/include/env_default.h b/include/env_default.h
index d05eba1..39c5b7c 100644
--- a/include/env_default.h
+++ b/include/env_default.h
@@ -41,6 +41,9 @@ const uchar default_environment[] = {
 #ifdef	CONFIG_ENV_CALLBACK_LIST_DEFAULT
 	ENV_CALLBACK_VAR "=" CONFIG_ENV_CALLBACK_LIST_DEFAULT "\0"
 #endif
+#ifdef	CONFIG_ENV_FLAGS_LIST_DEFAULT
+	ENV_FLAGS_VAR "=" CONFIG_ENV_FLAGS_LIST_DEFAULT "\0"
+#endif
 #ifdef	CONFIG_BOOTARGS
 	"bootargs="	CONFIG_BOOTARGS			"\0"
 #endif
diff --git a/include/env_flags.h b/include/env_flags.h
new file mode 100644
index 0000000..bf25f27
--- /dev/null
+++ b/include/env_flags.h
@@ -0,0 +1,76 @@
+/*
+ * (C) Copyright 2012
+ * Joe Hershberger, National Instruments, joe.hershberger at 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
+ */
+
+#ifndef __ENV_FLAGS_H__
+#define __ENV_FLAGS_H__
+
+enum env_flags_vartype {
+	env_flags_vartype_string,
+	env_flags_vartype_decimal,
+	env_flags_vartype_hex,
+	env_flags_vartype_bool,
+#ifdef CONFIG_CMD_NET
+	env_flags_vartype_ipaddr,
+	env_flags_vartype_macaddr,
+#endif
+	env_flags_vartype_end
+};
+
+#define ENV_FLAGS_VAR ".flags"
+#define ENV_FLAGS_ATTR_MAX_LEN 2
+#define ENV_FLAGS_VARTYPE_LOC 0
+
+#ifndef CONFIG_ENV_FLAGS_LIST_STATIC
+#define CONFIG_ENV_FLAGS_LIST_STATIC ""
+#endif
+
+#define ENV_FLAGS_LIST_STATIC \
+	CONFIG_ENV_FLAGS_LIST_STATIC
+
+/*
+ * Parse the flags string from a .flags attribute list into the vartype enum.
+ */
+enum env_flags_vartype env_flags_parse_vartype(const char *flags);
+
+#include <search.h>
+
+/*
+ * When adding a variable to the environment, initialize the flags for that
+ * variable.
+ */
+void env_flags_init(ENTRY *var_entry);
+
+/*
+ * Validate the newval for to conform with the requirements defined by its flags
+ */
+int env_flags_validate(const ENTRY *item, const char *newval, enum env_op op,
+	int flag);
+
+/*
+ * These are the binary flags used in the environment entry->flags variable to
+ * decribe properties of veriables in the table
+ */
+#define ENV_FLAGS_VARTYPE_BIN_MASK	0x00000007
+/* The actual variable type values use the enum value (within the mask) */
+
+#endif /* __ENV_FLAGS_H__ */
diff --git a/include/environment.h b/include/environment.h
index 6c30215..00e59ba 100644
--- a/include/environment.h
+++ b/include/environment.h
@@ -166,6 +166,7 @@ extern void env_reloc(void);
 
 #include <env_attr.h>
 #include <env_callback.h>
+#include <env_flags.h>
 #include <search.h>
 
 extern struct hsearch_data env_htab;
@@ -189,14 +190,6 @@ int set_default_vars(int nvars, char * const vars[]);
 /* Import from binary representation into hash table */
 int env_import(const char *buf, int check);
 
-/*
- * Check if variable "item" can be changed to newval
- * When (flag & H_FORCE) is set, it does not print out any error
- * message and forces overwriting of write-once variables.
- */
-int env_change_ok(const ENTRY *item, const char *newval, enum env_op op,
-	int flag);
-
 #endif /* DO_DEPS_ONLY */
 
 #endif /* _ENVIRONMENT_H_ */
diff --git a/include/search.h b/include/search.h
index d68e24a..13d3be6 100644
--- a/include/search.h
+++ b/include/search.h
@@ -49,6 +49,7 @@ typedef struct entry {
 	char *data;
 	int (*callback)(const char *name, const char *value, enum env_op op,
 		int flags);
+	int flags;
 } ENTRY;
 
 /* Opaque type for internal use.  */
diff --git a/lib/hashtable.c b/lib/hashtable.c
index e922666..07ebfb2 100644
--- a/lib/hashtable.c
+++ b/lib/hashtable.c
@@ -55,6 +55,7 @@
 #endif
 
 #include <env_callback.h>
+#include <env_flags.h>
 #include <search.h>
 
 /*
@@ -412,6 +413,8 @@ int hsearch_r(ENTRY item, ACTION action, ENTRY ** retval,
 
 		/* This is a new entry, so look up a possible callback */
 		env_callback_init(&htab->table[idx].entry);
+		/* Also look for flags */
+		env_flags_init(&htab->table[idx].entry);
 
 		/* check for permission */
 		if (htab->change_ok != NULL && htab->change_ok(
@@ -465,6 +468,7 @@ static void _hdelete(const char *key, struct hsearch_data *htab, ENTRY *ep,
 	free((void *)ep->key);
 	free(ep->data);
 	ep->callback = NULL;
+	ep->flags = 0;
 	htab->table[idx].used = -1;
 
 	--htab->filled;
-- 
1.7.11.5

^ permalink raw reply related	[flat|nested] 124+ messages in thread

* [U-Boot] [PATCH v4 15/20] tools/env: Add environment variable flags support
  2012-12-05  1:52                                         ` [U-Boot] [PATCH v4 0/20] " Joe Hershberger
                                                             ` (13 preceding siblings ...)
  2012-12-05  1:52                                           ` [U-Boot] [PATCH v4 14/20] env: Add environment variable flags Joe Hershberger
@ 2012-12-05  1:52                                           ` Joe Hershberger
  2012-12-05  1:52                                           ` [U-Boot] [PATCH v4 16/20] env: Add a command to display details about env flags Joe Hershberger
                                                             ` (6 subsequent siblings)
  21 siblings, 0 replies; 124+ messages in thread
From: Joe Hershberger @ 2012-12-05  1:52 UTC (permalink / raw)
  To: u-boot

Currently just validates variable types as decimal, hexidecimal,
boolean, ip address, and mac address.  Call
env_acl_validate_setenv_params() from setenv() in fw_env.c.

If the entry is not found in the env .flags, then look in the static
one. This allows the env to override the static definitions, but prevents
the need to have every definition in the environment distracting you.

Need to build in _ctype for isdigit for Linux.

Signed-off-by: Joe Hershberger <joe.hershberger@ni.com>
---
Changes in v4: None
Changes in v3: None
Changes in v2: None

 common/env_attr.c   |  7 +++++
 common/env_flags.c  | 75 +++++++++++++++++++++++++++++++++++++++++++++++++++++
 include/env_flags.h | 19 ++++++++++++++
 tools/env/Makefile  |  3 +++
 tools/env/fw_env.c  |  9 +++++++
 5 files changed, 113 insertions(+)

diff --git a/common/env_attr.c b/common/env_attr.c
index 7d330a5..210c98d 100644
--- a/common/env_attr.c
+++ b/common/env_attr.c
@@ -21,7 +21,14 @@
  * MA 02111-1307 USA
  */
 
+#ifdef USE_HOSTCC /* Eliminate "ANSI does not permit..." warnings */
+#include <stdint.h>
+#include <stdio.h>
+#include <linux/linux_string.h>
+#else
 #include <common.h>
+#endif
+
 #include <env_attr.h>
 #include <errno.h>
 #include <linux/string.h>
diff --git a/common/env_flags.c b/common/env_flags.c
index 2292569..6ea995a 100644
--- a/common/env_flags.c
+++ b/common/env_flags.c
@@ -24,8 +24,17 @@
 #include <linux/string.h>
 #include <linux/ctype.h>
 
+#ifdef USE_HOSTCC /* Eliminate "ANSI does not permit..." warnings */
+#include <stdint.h>
+#include <stdio.h>
+#include "fw_env.h"
+#include <env_attr.h>
+#include <env_flags.h>
+#define getenv fw_getenv
+#else
 #include <common.h>
 #include <environment.h>
+#endif
 
 #ifdef CONFIG_CMD_NET
 #define ENV_FLAGS_NET_VARTYPE_REPS "im"
@@ -174,6 +183,70 @@ static inline int env_flags_lookup(const char *flags_list, const char *name,
 	return ret;
 }
 
+#ifdef USE_HOSTCC /* Functions only used from tools/env */
+/*
+ * Look up any flags directly from the .flags variable and the static list
+ * and convert them to the vartype enum.
+ */
+enum env_flags_vartype env_flags_get_type(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_vartype_string;
+
+	if (strlen(flags) <= ENV_FLAGS_VARTYPE_LOC)
+		return env_flags_vartype_string;
+
+	return env_flags_parse_vartype(flags);
+}
+
+/*
+ * Validate that the proposed new value for "name" is valid according to the
+ * defined flags for that variable, if any.
+ */
+int env_flags_validate_type(const char *name, const char *value)
+{
+	enum env_flags_vartype type;
+
+	if (value == NULL)
+		return 0;
+	type = env_flags_get_type(name);
+	if (_env_flags_validate_type(value, type) < 0) {
+		printf("## Error: flags type check failure for "
+			"\"%s\" <= \"%s\" (type: %c)\n",
+			name, value, env_flags_vartype_rep[type]);
+		return -1;
+	}
+	return 0;
+}
+
+/*
+ * Validate the parameters to "env set" directly
+ */
+int env_flags_validate_env_set_params(int argc, char * const argv[])
+{
+	if ((argc >= 3) && argv[2] != NULL) {
+		enum env_flags_vartype type = env_flags_get_type(argv[1]);
+
+		/*
+		 * we don't currently check types that need more than
+		 * one argument
+		 */
+		if (type != env_flags_vartype_string && argc > 3) {
+			printf("## Error: too many parameters for setting "
+				"\"%s\"\n", argv[1]);
+			return -1;
+		}
+		return env_flags_validate_type(argv[1], argv[2]);
+	}
+	/* ok */
+	return 0;
+}
+
+#else /* !USE_HOSTCC - Functions only used from lib/hashtable.c */
+
 /*
  * Parse the flag charachters from the .flags attribute list into the binary
  * form to be stored in the environment entry->flags field.
@@ -312,3 +385,5 @@ int env_flags_validate(const ENTRY *item, const char *newval, enum env_op op,
 
 	return 0;
 }
+
+#endif
diff --git a/include/env_flags.h b/include/env_flags.h
index bf25f27..3333446 100644
--- a/include/env_flags.h
+++ b/include/env_flags.h
@@ -52,6 +52,23 @@ enum env_flags_vartype {
  */
 enum env_flags_vartype env_flags_parse_vartype(const char *flags);
 
+#ifdef USE_HOSTCC
+/*
+ * Look up the type of a variable directly from the .flags var.
+ */
+enum env_flags_vartype env_flags_get_type(const char *name);
+/*
+ * Validate the newval for its type to conform with the requirements defined by
+ * its flags (directly looked at the .flags var).
+ */
+int env_flags_validate_type(const char *name, const char *newval);
+/*
+ * Validate the parameters passed to "env set" for type compliance
+ */
+int env_flags_validate_env_set_params(int argc, char * const argv[]);
+
+#else /* !USE_HOSTCC */
+
 #include <search.h>
 
 /*
@@ -73,4 +90,6 @@ int env_flags_validate(const ENTRY *item, const char *newval, enum env_op op,
 #define ENV_FLAGS_VARTYPE_BIN_MASK	0x00000007
 /* The actual variable type values use the enum value (within the mask) */
 
+#endif /* USE_HOSTCC */
+
 #endif /* __ENV_FLAGS_H__ */
diff --git a/tools/env/Makefile b/tools/env/Makefile
index ab73c8c..0e798e0 100644
--- a/tools/env/Makefile
+++ b/tools/env/Makefile
@@ -24,12 +24,15 @@
 include $(TOPDIR)/config.mk
 
 HOSTSRCS := $(SRCTREE)/lib/crc32.c  fw_env.c  fw_env_main.c
+HOSTSRCS += $(SRCTREE)/lib/ctype.c $(SRCTREE)/lib/linux_string.c
+HOSTSRCS += $(SRCTREE)/common/env_attr.c $(SRCTREE)/common/env_flags.c
 HEADERS	:= fw_env.h $(OBJTREE)/include/config.h
 
 # Compile for a hosted environment on the target
 HOSTCPPFLAGS  = -idirafter $(SRCTREE)/include \
 		-idirafter $(OBJTREE)/include2 \
 		-idirafter $(OBJTREE)/include \
+		-idirafter $(SRCTREE)/tools/env \
 		-DUSE_HOSTCC \
 		-DTEXT_BASE=$(TEXT_BASE)
 
diff --git a/tools/env/fw_env.c b/tools/env/fw_env.c
index 9b023e8..5be36fc 100644
--- a/tools/env/fw_env.c
+++ b/tools/env/fw_env.c
@@ -25,6 +25,7 @@
  */
 
 #include <errno.h>
+#include <env_flags.h>
 #include <fcntl.h>
 #include <linux/stringify.h>
 #include <stdio.h>
@@ -395,6 +396,9 @@ int fw_setenv(int argc, char *argv[])
 
 	name = argv[1];
 
+	if (env_flags_validate_env_set_params(argc, argv) < 0)
+		return 1;
+
 	len = 0;
 	for (i = 2; i < argc; ++i) {
 		char *val = argv[i];
@@ -516,6 +520,11 @@ int fw_parse_script(char *fname)
 			name, val ? val : " removed");
 #endif
 
+		if (env_flags_validate_type(name, val) < 0) {
+			ret = -1;
+			break;
+		}
+
 		/*
 		 * If there is an error setting a variable,
 		 * try to save the environment and returns an error
-- 
1.7.11.5

^ permalink raw reply related	[flat|nested] 124+ messages in thread

* [U-Boot] [PATCH v4 16/20] env: Add a command to display details about env flags
  2012-12-05  1:52                                         ` [U-Boot] [PATCH v4 0/20] " Joe Hershberger
                                                             ` (14 preceding siblings ...)
  2012-12-05  1:52                                           ` [U-Boot] [PATCH v4 15/20] tools/env: Add environment variable flags support Joe Hershberger
@ 2012-12-05  1:52                                           ` Joe Hershberger
  2012-12-05  1:52                                           ` [U-Boot] [PATCH v4 17/20] env: Add support for access control to .flags Joe Hershberger
                                                             ` (5 subsequent siblings)
  21 siblings, 0 replies; 124+ messages in thread
From: Joe Hershberger @ 2012-12-05  1:52 UTC (permalink / raw)
  To: u-boot

Similar to the env callback command, this will show details about the
options available, the static list, and the currently active variables.

Signed-off-by: Joe Hershberger <joe.hershberger@ni.com>
---
Changes in v4:
- Add help text for env flags command

Changes in v3: None
Changes in v2: None

 README              |  1 +
 common/cmd_nvedit.c | 59 +++++++++++++++++++++++++++++++++++++++++++++++++++++
 common/env_flags.c  | 34 ++++++++++++++++++++++++++++++
 include/env_flags.h | 11 ++++++++++
 4 files changed, 105 insertions(+)

diff --git a/README b/README
index 5705925..efce998 100644
--- a/README
+++ b/README
@@ -811,6 +811,7 @@ The following options need to be configured:
 		CONFIG_CMD_EEPROM	* EEPROM read/write support
 		CONFIG_CMD_ELF		* bootelf, bootvx
 		CONFIG_CMD_ENV_CALLBACK	* display details about env callbacks
+		CONFIG_CMD_ENV_FLAGS	* display details about env flags
 		CONFIG_CMD_EXPORTENV	* export the environment
 		CONFIG_CMD_EXT2		* ext2 command support
 		CONFIG_CMD_EXT4		* ext4 command support
diff --git a/common/cmd_nvedit.c b/common/cmd_nvedit.c
index 4b2b040..9f2b01f 100644
--- a/common/cmd_nvedit.c
+++ b/common/cmd_nvedit.c
@@ -439,6 +439,59 @@ int do_env_callback(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
 }
 #endif
 
+#if defined(CONFIG_CMD_ENV_FLAGS)
+static int print_static_flags(const char *var_name, const char *flags)
+{
+	enum env_flags_vartype type = env_flags_parse_vartype(flags);
+
+	printf("\t%-20s %-20s\n", var_name, env_flags_get_vartype_name(type));
+
+	return 0;
+}
+
+static int print_active_flags(ENTRY *entry)
+{
+	enum env_flags_vartype type;
+
+	if (entry->flags == 0)
+		return 0;
+
+	type = (enum env_flags_vartype)
+		(entry->flags & ENV_FLAGS_VARTYPE_BIN_MASK);
+	printf("\t%-20s %-20s\n", entry->key, env_flags_get_vartype_name(type));
+
+	return 0;
+}
+
+/*
+ * Print the flags available and what variables have flags
+ */
+int do_env_flags(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
+{
+	/* Print the available variable types */
+	printf("Available variable type flags (position %d):\n",
+		ENV_FLAGS_VARTYPE_LOC);
+	puts("\tFlag\tVariable Type Name\n");
+	puts("\t----\t------------------\n");
+	env_flags_print_vartypes();
+	puts("\n");
+
+	/* Print the static flags that may exist */
+	puts("Static flags:\n");
+	printf("\t%-20s %-20s\n", "Variable Name", "Variable Type");
+	printf("\t%-20s %-20s\n", "-------------", "-------------");
+	env_attr_walk(ENV_FLAGS_LIST_STATIC, print_static_flags);
+	puts("\n");
+
+	/* walk through each variable and print the flags if non-default */
+	puts("Active flags:\n");
+	printf("\t%-20s %-20s\n", "Variable Name", "Variable Type");
+	printf("\t%-20s %-20s\n", "-------------", "-------------");
+	hwalk_r(&env_htab, print_active_flags);
+	return 0;
+}
+#endif
+
 /*
  * Interactively edit an environment variable
  */
@@ -909,6 +962,9 @@ static cmd_tbl_t cmd_env_sub[] = {
 #if defined(CONFIG_CMD_ENV_CALLBACK)
 	U_BOOT_CMD_MKENT(callback, 1, 0, do_env_callback, "", ""),
 #endif
+#if defined(CONFIG_CMD_ENV_FLAGS)
+	U_BOOT_CMD_MKENT(flags, 1, 0, do_env_flags, "", ""),
+#endif
 #if defined(CONFIG_CMD_EXPORTENV)
 	U_BOOT_CMD_MKENT(export, 4, 0, do_env_export, "", ""),
 #endif
@@ -970,6 +1026,9 @@ static char env_help_text[] =
 #if defined(CONFIG_CMD_EXPORTENV)
 	"env export [-t | -b | -c] [-s size] addr [var ...] - export environment\n"
 #endif
+#if defined(CONFIG_CMD_ENV_FLAGS)
+	"env flags - print variables that have non-default flags\n"
+#endif
 #if defined(CONFIG_CMD_GREPENV)
 	"env grep string [...] - search environment\n"
 #endif
diff --git a/common/env_flags.c b/common/env_flags.c
index 6ea995a..7afc423 100644
--- a/common/env_flags.c
+++ b/common/env_flags.c
@@ -43,6 +43,40 @@
 #endif
 
 static const char env_flags_vartype_rep[] = "sdxb" ENV_FLAGS_NET_VARTYPE_REPS;
+#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
+};
+
+/*
+ * 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++;
+	}
+}
+
+/*
+ * Return the name of the type.
+ */
+const char *env_flags_get_vartype_name(enum env_flags_vartype type)
+{
+	return env_flags_vartype_names[type];
+}
+#endif /* CONFIG_CMD_ENV_FLAGS */
 
 /*
  * Parse the flags string from a .flags attribute list into the vartype enum.
diff --git a/include/env_flags.h b/include/env_flags.h
index 3333446..7e72523 100644
--- a/include/env_flags.h
+++ b/include/env_flags.h
@@ -47,6 +47,17 @@ enum env_flags_vartype {
 #define ENV_FLAGS_LIST_STATIC \
 	CONFIG_ENV_FLAGS_LIST_STATIC
 
+#ifdef CONFIG_CMD_ENV_FLAGS
+/*
+ * Print the whole list of available type flags.
+ */
+void env_flags_print_vartypes(void);
+/*
+ * Return the name of the type.
+ */
+const char *env_flags_get_vartype_name(enum env_flags_vartype type);
+#endif
+
 /*
  * Parse the flags string from a .flags attribute list into the vartype enum.
  */
-- 
1.7.11.5

^ permalink raw reply related	[flat|nested] 124+ messages in thread

* [U-Boot] [PATCH v4 17/20] env: Add support for access control to .flags
  2012-12-05  1:52                                         ` [U-Boot] [PATCH v4 0/20] " Joe Hershberger
                                                             ` (15 preceding siblings ...)
  2012-12-05  1:52                                           ` [U-Boot] [PATCH v4 16/20] env: Add a command to display details about env flags Joe Hershberger
@ 2012-12-05  1:52                                           ` Joe Hershberger
  2012-12-05  1:52                                           ` [U-Boot] [PATCH v4 18/20] env: Add setenv force support Joe Hershberger
                                                             ` (4 subsequent siblings)
  21 siblings, 0 replies; 124+ messages in thread
From: Joe Hershberger @ 2012-12-05  1:52 UTC (permalink / raw)
  To: u-boot

Add support for read-only, write-once, and change-default.

Signed-off-by: Joe Hershberger <joe.hershberger@ni.com>
---
Changes in v4: None
Changes in v3: None
Changes in v2: None

 README                |  13 ++++-
 common/cmd_nvedit.c   |  31 ++++++++--
 common/env_common.c   |  18 ++++++
 common/env_flags.c    | 153 ++++++++++++++++++++++++++++++++++++++++++++++++--
 include/env_flags.h   |  50 ++++++++++++++++-
 include/environment.h |   3 +
 tools/env/fw_env.c    |  74 ++++++++++++++++++++++--
 7 files changed, 324 insertions(+), 18 deletions(-)

diff --git a/README b/README
index efce998..28abf89 100644
--- a/README
+++ b/README
@@ -3083,7 +3083,8 @@ Configuration Settings:
 
 	The format of the list is:
 		type_attribute = [s|d|x|b|i|m]
-		attributes = type_attribute
+		access_atribute = [a|r|o|c]
+		attributes = type_attribute[access_atribute]
 		entry = variable_name[:attributes]
 		list = entry[,list]
 
@@ -3095,6 +3096,12 @@ Configuration Settings:
 		i - IP address
 		m - MAC address
 
+	The access attributes are:
+		a - Any (default)
+		r - Read-only
+		o - Write-once
+		c - Change-default
+
 	- CONFIG_ENV_FLAGS_LIST_DEFAULT
 		Define this to a list (string) to define the ".flags"
 		envirnoment variable in the default or embedded environment.
@@ -3106,6 +3113,10 @@ Configuration Settings:
 		list, simply add an entry for the same variable name to the
 		".flags" variable.
 
+- CONFIG_ENV_ACCESS_IGNORE_FORCE
+	If defined, don't allow the -f switch to env set override variable
+	access flags.
+
 The following definitions that deal with the placement and management
 of environment data (variable area); in general, we support the
 following configurations:
diff --git a/common/cmd_nvedit.c b/common/cmd_nvedit.c
index 9f2b01f..a78627d 100644
--- a/common/cmd_nvedit.c
+++ b/common/cmd_nvedit.c
@@ -443,8 +443,11 @@ int do_env_callback(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
 static int print_static_flags(const char *var_name, const char *flags)
 {
 	enum env_flags_vartype type = env_flags_parse_vartype(flags);
+	enum env_flags_varaccess access = env_flags_parse_varaccess(flags);
 
-	printf("\t%-20s %-20s\n", var_name, env_flags_get_vartype_name(type));
+	printf("\t%-20s %-20s %-20s\n", var_name,
+		env_flags_get_vartype_name(type),
+		env_flags_get_varaccess_name(access));
 
 	return 0;
 }
@@ -452,13 +455,17 @@ static int print_static_flags(const char *var_name, const char *flags)
 static int print_active_flags(ENTRY *entry)
 {
 	enum env_flags_vartype type;
+	enum env_flags_varaccess access;
 
 	if (entry->flags == 0)
 		return 0;
 
 	type = (enum env_flags_vartype)
 		(entry->flags & ENV_FLAGS_VARTYPE_BIN_MASK);
-	printf("\t%-20s %-20s\n", entry->key, env_flags_get_vartype_name(type));
+	access = env_flags_parse_varaccess_from_binflags(entry->flags);
+	printf("\t%-20s %-20s %-20s\n", entry->key,
+		env_flags_get_vartype_name(type),
+		env_flags_get_varaccess_name(access));
 
 	return 0;
 }
@@ -476,17 +483,29 @@ int do_env_flags(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
 	env_flags_print_vartypes();
 	puts("\n");
 
+	/* Print the available variable access types */
+	printf("Available variable access flags (position %d):\n",
+		ENV_FLAGS_VARACCESS_LOC);
+	puts("\tFlag\tVariable Access Name\n");
+	puts("\t----\t--------------------\n");
+	env_flags_print_varaccess();
+	puts("\n");
+
 	/* Print the static flags that may exist */
 	puts("Static flags:\n");
-	printf("\t%-20s %-20s\n", "Variable Name", "Variable Type");
-	printf("\t%-20s %-20s\n", "-------------", "-------------");
+	printf("\t%-20s %-20s %-20s\n", "Variable Name", "Variable Type",
+		"Variable Access");
+	printf("\t%-20s %-20s %-20s\n", "-------------", "-------------",
+		"---------------");
 	env_attr_walk(ENV_FLAGS_LIST_STATIC, print_static_flags);
 	puts("\n");
 
 	/* walk through each variable and print the flags if non-default */
 	puts("Active flags:\n");
-	printf("\t%-20s %-20s\n", "Variable Name", "Variable Type");
-	printf("\t%-20s %-20s\n", "-------------", "-------------");
+	printf("\t%-20s %-20s %-20s\n", "Variable Name", "Variable Type",
+		"Variable Access");
+	printf("\t%-20s %-20s %-20s\n", "-------------", "-------------",
+		"---------------");
 	hwalk_r(&env_htab, print_active_flags);
 	return 0;
 }
diff --git a/common/env_common.c b/common/env_common.c
index b711337..3021efe 100644
--- a/common/env_common.c
+++ b/common/env_common.c
@@ -95,6 +95,24 @@ int getenv_yesno(const char *var)
 		1 : 0;
 }
 
+/*
+ * Look up the variable from the default environment
+ */
+char *getenv_default(const char *name)
+{
+	char *ret_val;
+	unsigned long really_valid = gd->env_valid;
+	unsigned long real_gd_flags = gd->flags;
+
+	/* Pretend that the image is bad. */
+	gd->flags &= ~GD_FLG_ENV_READY;
+	gd->env_valid = 0;
+	ret_val = getenv(name);
+	gd->env_valid = really_valid;
+	gd->flags = real_gd_flags;
+	return ret_val;
+}
+
 void set_default_env(const char *s)
 {
 	int flags = 0;
diff --git a/common/env_flags.c b/common/env_flags.c
index 7afc423..9bf7f2d 100644
--- a/common/env_flags.c
+++ b/common/env_flags.c
@@ -43,6 +43,17 @@
 #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",
@@ -54,6 +65,12 @@ static const char * const env_flags_vartype_names[] = {
 	"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.
@@ -70,12 +87,34 @@ void env_flags_print_vartypes(void)
 }
 
 /*
+ * 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 */
 
 /*
@@ -95,6 +134,40 @@ 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 = 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;
+
+	puts("Warning: Non-standard access flags.\n");
+
+	return env_flags_varaccess_any;
+}
+
 static inline int is_hex_prefix(const char *value)
 {
 	return value[0] == '0' && (value[1] == 'x' || value[1] == 'X');
@@ -237,6 +310,23 @@ enum env_flags_vartype env_flags_get_type(const char *name)
 }
 
 /*
+ * 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.
  */
@@ -257,6 +347,21 @@ int env_flags_validate_type(const char *name, const char *value)
 }
 
 /*
+ * 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
  */
 int env_flags_validate_env_set_params(int argc, char * const argv[])
@@ -287,7 +392,12 @@ 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;
 }
 
 /*
@@ -372,13 +482,10 @@ 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;
 
@@ -417,6 +524,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;
 }
 
diff --git a/include/env_flags.h b/include/env_flags.h
index 7e72523..0bdae07 100644
--- a/include/env_flags.h
+++ b/include/env_flags.h
@@ -36,9 +36,18 @@ enum env_flags_vartype {
 	env_flags_vartype_end
 };
 
+enum env_flags_varaccess {
+	env_flags_varaccess_any,
+	env_flags_varaccess_readonly,
+	env_flags_varaccess_writeonce,
+	env_flags_varaccess_changedefault,
+	env_flags_varaccess_end
+};
+
 #define ENV_FLAGS_VAR ".flags"
 #define ENV_FLAGS_ATTR_MAX_LEN 2
 #define ENV_FLAGS_VARTYPE_LOC 0
+#define ENV_FLAGS_VARACCESS_LOC 1
 
 #ifndef CONFIG_ENV_FLAGS_LIST_STATIC
 #define CONFIG_ENV_FLAGS_LIST_STATIC ""
@@ -53,15 +62,31 @@ enum env_flags_vartype {
  */
 void env_flags_print_vartypes(void);
 /*
+ * Print the whole list of available access flags.
+ */
+void env_flags_print_varaccess(void);
+/*
  * Return the name of the type.
  */
 const char *env_flags_get_vartype_name(enum env_flags_vartype type);
+/*
+ * Return the name of the access.
+ */
+const char *env_flags_get_varaccess_name(enum env_flags_varaccess access);
 #endif
 
 /*
  * Parse the flags string from a .flags attribute list into the vartype enum.
  */
 enum env_flags_vartype env_flags_parse_vartype(const char *flags);
+/*
+ * Parse the flags string from a .flags attribute list into the varaccess enum.
+ */
+enum env_flags_varaccess env_flags_parse_varaccess(const char *flags);
+/*
+ * 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);
 
 #ifdef USE_HOSTCC
 /*
@@ -69,11 +94,25 @@ enum env_flags_vartype env_flags_parse_vartype(const char *flags);
  */
 enum env_flags_vartype env_flags_get_type(const char *name);
 /*
+ * Look up the access of a variable directly from the .flags var.
+ */
+enum env_flags_varaccess env_flags_get_access(const char *name);
+/*
  * Validate the newval for its type to conform with the requirements defined by
  * its flags (directly looked at the .flags var).
  */
 int env_flags_validate_type(const char *name, const char *newval);
 /*
+ * Validate the newval for its access to conform with the requirements defined
+ * by its flags (directly looked at the .flags var).
+ */
+int env_flags_validate_access(const char *name, int check_mask);
+/*
+ * 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);
+/*
  * Validate the parameters passed to "env set" for type compliance
  */
 int env_flags_validate_env_set_params(int argc, char * const argv[]);
@@ -94,13 +133,18 @@ void env_flags_init(ENTRY *var_entry);
 int env_flags_validate(const ENTRY *item, const char *newval, enum env_op op,
 	int flag);
 
+#endif /* USE_HOSTCC */
+
 /*
  * These are the binary flags used in the environment entry->flags variable to
  * decribe properties of veriables in the table
  */
-#define ENV_FLAGS_VARTYPE_BIN_MASK	0x00000007
+#define ENV_FLAGS_VARTYPE_BIN_MASK			0x00000007
 /* The actual variable type values use the enum value (within the mask) */
-
-#endif /* USE_HOSTCC */
+#define ENV_FLAGS_VARACCESS_PREVENT_DELETE		0x00000008
+#define ENV_FLAGS_VARACCESS_PREVENT_CREATE		0x00000010
+#define ENV_FLAGS_VARACCESS_PREVENT_OVERWR		0x00000020
+#define ENV_FLAGS_VARACCESS_PREVENT_NONDEF_OVERWR	0x00000040
+#define ENV_FLAGS_VARACCESS_BIN_MASK			0x00000078
 
 #endif /* __ENV_FLAGS_H__ */
diff --git a/include/environment.h b/include/environment.h
index 00e59ba..e64b43d 100644
--- a/include/environment.h
+++ b/include/environment.h
@@ -181,6 +181,9 @@ unsigned char env_get_char_memory(int index);
 /* Function that updates CRC of the enironment */
 void env_crc_update(void);
 
+/* Look up the variable from the default environment */
+char *getenv_default(const char *name);
+
 /* [re]set to the default environment */
 void set_default_env(const char *s);
 
diff --git a/tools/env/fw_env.c b/tools/env/fw_env.c
index 5be36fc..a596a1b 100644
--- a/tools/env/fw_env.c
+++ b/tools/env/fw_env.c
@@ -182,6 +182,32 @@ char *fw_getenv (char *name)
 }
 
 /*
+ * Search the default environment for a variable.
+ * Return the value, if found, or NULL, if not found.
+ */
+char *fw_getdefenv(char *name)
+{
+	char *env, *nxt;
+
+	for (env = default_environment; *env; env = nxt + 1) {
+		char *val;
+
+		for (nxt = env; *nxt; ++nxt) {
+			if (nxt >= &default_environment[ENV_SIZE]) {
+				fprintf(stderr, "## Error: "
+					"default environment not terminated\n");
+				return NULL;
+			}
+		}
+		val = envmatch(name, env);
+		if (!val)
+			continue;
+		return val;
+	}
+	return NULL;
+}
+
+/*
  * Print the current definition of one, or more, or all
  * environment variables
  */
@@ -282,6 +308,7 @@ int fw_env_write(char *name, char *value)
 	int len;
 	char *env, *nxt;
 	char *oldval = NULL;
+	int deleting, creating, overwriting;
 
 	/*
 	 * search if variable with this name already exists
@@ -299,10 +326,49 @@ int fw_env_write(char *name, char *value)
 			break;
 	}
 
-	/*
-	 * Delete any existing definition
-	 */
-	if (oldval) {
+	deleting = (oldval && !(value && strlen(value)));
+	creating = (!oldval && (value && strlen(value)));
+	overwriting = (oldval && (value && strlen(value)));
+
+	/* check for permission */
+	if (deleting) {
+		if (env_flags_validate_varaccess(name,
+		    ENV_FLAGS_VARACCESS_PREVENT_DELETE)) {
+			printf("Can't delete \"%s\"\n", name);
+			errno = EROFS;
+			return -1;
+		}
+	} else if (overwriting) {
+		if (env_flags_validate_varaccess(name,
+		    ENV_FLAGS_VARACCESS_PREVENT_OVERWR)) {
+			printf("Can't overwrite \"%s\"\n", name);
+			errno = EROFS;
+			return -1;
+		} else if (env_flags_validate_varaccess(name,
+		    ENV_FLAGS_VARACCESS_PREVENT_NONDEF_OVERWR)) {
+			const char *defval = fw_getdefenv(name);
+
+			if (defval == NULL)
+				defval = "";
+			if (strcmp(oldval, defval)
+			    != 0) {
+				printf("Can't overwrite \"%s\"\n", name);
+				errno = EROFS;
+				return -1;
+			}
+		}
+	} else if (creating) {
+		if (env_flags_validate_varaccess(name,
+		    ENV_FLAGS_VARACCESS_PREVENT_CREATE)) {
+			printf("Can't create \"%s\"\n", name);
+			errno = EROFS;
+			return -1;
+		}
+	} else
+		/* Nothing to do */
+		return 0;
+
+	if (deleting || overwriting) {
 #ifndef CONFIG_ENV_OVERWRITE
 		/*
 		 * Ethernet Address and serial# can be set only once
-- 
1.7.11.5

^ permalink raw reply related	[flat|nested] 124+ messages in thread

* [U-Boot] [PATCH v4 18/20] env: Add setenv force support
  2012-12-05  1:52                                         ` [U-Boot] [PATCH v4 0/20] " Joe Hershberger
                                                             ` (16 preceding siblings ...)
  2012-12-05  1:52                                           ` [U-Boot] [PATCH v4 17/20] env: Add support for access control to .flags Joe Hershberger
@ 2012-12-05  1:52                                           ` Joe Hershberger
  2012-12-05  1:52                                           ` [U-Boot] [PATCH v4 19/20] env: Implement the env delete command Joe Hershberger
                                                             ` (3 subsequent siblings)
  21 siblings, 0 replies; 124+ messages in thread
From: Joe Hershberger @ 2012-12-05  1:52 UTC (permalink / raw)
  To: u-boot

Now that we have support for permissions, add a way to override them.

Signed-off-by: Joe Hershberger <joe.hershberger@ni.com>
---
Changes in v4:
- Add force support to setenv

Changes in v3: None
Changes in v2: None

 common/cmd_nvedit.c | 29 +++++++++++++++++++++++------
 1 file changed, 23 insertions(+), 6 deletions(-)

diff --git a/common/cmd_nvedit.c b/common/cmd_nvedit.c
index a78627d..3de1d5b 100644
--- a/common/cmd_nvedit.c
+++ b/common/cmd_nvedit.c
@@ -200,7 +200,24 @@ static int _do_env_set(int flag, int argc, char * const argv[])
 	int   i, len;
 	char  *name, *value, *s;
 	ENTRY e, *ep;
+	int env_flag = H_INTERACTIVE;
 
+	debug("Initial value for argc=%d\n", argc);
+	while (argc > 1 && **(argv + 1) == '-') {
+		char *arg = *++argv;
+
+		--argc;
+		while (*++arg) {
+			switch (*arg) {
+			case 'f':		/* force */
+				env_flag |= H_FORCE;
+				break;
+			default:
+				return CMD_RET_USAGE;
+			}
+		}
+	}
+	debug("Final value for argc=%d\n", argc);
 	name = argv[1];
 	value = argv[2];
 
@@ -214,7 +231,7 @@ static int _do_env_set(int flag, int argc, char * const argv[])
 
 	/* Delete only ? */
 	if (argc < 3 || argv[2] == NULL) {
-		int rc = hdelete_r(name, &env_htab, H_INTERACTIVE);
+		int rc = hdelete_r(name, &env_htab, env_flag);
 		return !rc;
 	}
 
@@ -241,7 +258,7 @@ static int _do_env_set(int flag, int argc, char * const argv[])
 
 	e.key	= name;
 	e.data	= value;
-	hsearch_r(e, ENTER, &ep, &env_htab, H_INTERACTIVE);
+	hsearch_r(e, ENTER, &ep, &env_htab, env_flag);
 	free(value);
 	if (!ep) {
 		printf("## Error inserting \"%s\" variable, errno=%d\n",
@@ -1105,10 +1122,10 @@ U_BOOT_CMD_COMPLETE(
 U_BOOT_CMD_COMPLETE(
 	setenv, CONFIG_SYS_MAXARGS, 0,	do_env_set,
 	"set environment variables",
-	"name value ...\n"
-	"    - set environment variable 'name' to 'value ...'\n"
-	"setenv name\n"
-	"    - delete environment variable 'name'",
+	"[-f] name value ...\n"
+	"    - [forcibly] set environment variable 'name' to 'value ...'\n"
+	"setenv [-f] name\n"
+	"    - [forcibly] delete environment variable 'name'",
 	var_complete
 );
 
-- 
1.7.11.5

^ permalink raw reply related	[flat|nested] 124+ messages in thread

* [U-Boot] [PATCH v4 19/20] env: Implement the env delete command
  2012-12-05  1:52                                         ` [U-Boot] [PATCH v4 0/20] " Joe Hershberger
                                                             ` (17 preceding siblings ...)
  2012-12-05  1:52                                           ` [U-Boot] [PATCH v4 18/20] env: Add setenv force support Joe Hershberger
@ 2012-12-05  1:52                                           ` Joe Hershberger
  2012-12-05  1:52                                           ` [U-Boot] [PATCH v4 20/20] env: Handle write-once ethaddr and serial# generically Joe Hershberger
                                                             ` (2 subsequent siblings)
  21 siblings, 0 replies; 124+ messages in thread
From: Joe Hershberger @ 2012-12-05  1:52 UTC (permalink / raw)
  To: u-boot

Implement a way to delete more than one variable at a time.

Signed-off-by: Joe Hershberger <joe.hershberger@ni.com>
---
Changes in v4:
- Implement delete

Changes in v3: None
Changes in v2: None

 common/cmd_nvedit.c | 35 ++++++++++++++++++++++++++++++++---
 1 file changed, 32 insertions(+), 3 deletions(-)

diff --git a/common/cmd_nvedit.c b/common/cmd_nvedit.c
index 3de1d5b..3bfaa46 100644
--- a/common/cmd_nvedit.c
+++ b/common/cmd_nvedit.c
@@ -721,8 +721,36 @@ static int do_env_default(cmd_tbl_t *cmdtp, int __flag,
 static int do_env_delete(cmd_tbl_t *cmdtp, int flag,
 			 int argc, char * const argv[])
 {
-	printf("Not implemented yet\n");
-	return 0;
+	int env_flag = H_INTERACTIVE;
+	int ret = 0;
+
+	debug("Initial value for argc=%d\n", argc);
+	while (argc > 1 && **(argv + 1) == '-') {
+		char *arg = *++argv;
+
+		--argc;
+		while (*++arg) {
+			switch (*arg) {
+			case 'f':		/* force */
+				env_flag |= H_FORCE;
+				break;
+			default:
+				return CMD_RET_USAGE;
+			}
+		}
+	}
+	debug("Final value for argc=%d\n", argc);
+
+	env_id++;
+
+	while (--argc > 0) {
+		char *name = *++argv;
+
+		if (!hdelete_r(name, &env_htab, env_flag))
+			ret = 1;
+	}
+
+	return ret;
 }
 
 #ifdef CONFIG_CMD_EXPORTENV
@@ -991,7 +1019,7 @@ static cmd_tbl_t cmd_env_sub[] = {
 	U_BOOT_CMD_MKENT(ask, CONFIG_SYS_MAXARGS, 1, do_env_ask, "", ""),
 #endif
 	U_BOOT_CMD_MKENT(default, 1, 0, do_env_default, "", ""),
-	U_BOOT_CMD_MKENT(delete, 2, 0, do_env_delete, "", ""),
+	U_BOOT_CMD_MKENT(delete, CONFIG_SYS_MAXARGS, 0, do_env_delete, "", ""),
 #if defined(CONFIG_CMD_EDITENV)
 	U_BOOT_CMD_MKENT(edit, 2, 0, do_env_edit, "", ""),
 #endif
@@ -1056,6 +1084,7 @@ static char env_help_text[] =
 #endif
 	"default [-f] -a - [forcibly] reset default environment\n"
 	"env default [-f] var [...] - [forcibly] reset variable(s) to their default values\n"
+	"env delete [-f] var [...] - [forcibly] delete variable(s)\n"
 #if defined(CONFIG_CMD_EDITENV)
 	"env edit name - edit environment variable\n"
 #endif
-- 
1.7.11.5

^ permalink raw reply related	[flat|nested] 124+ messages in thread

* [U-Boot] [PATCH v4 20/20] env: Handle write-once ethaddr and serial# generically
  2012-12-05  1:52                                         ` [U-Boot] [PATCH v4 0/20] " Joe Hershberger
                                                             ` (18 preceding siblings ...)
  2012-12-05  1:52                                           ` [U-Boot] [PATCH v4 19/20] env: Implement the env delete command Joe Hershberger
@ 2012-12-05  1:52                                           ` Joe Hershberger
  2012-12-11 16:51                                           ` [U-Boot] [PATCH v4 0/20] Add environment call-back and flags capability Tom Rini
  2012-12-12  4:16                                           ` [U-Boot] [PATCH v5 " Joe Hershberger
  21 siblings, 0 replies; 124+ messages in thread
From: Joe Hershberger @ 2012-12-05  1:52 UTC (permalink / raw)
  To: u-boot

Use the variable access flags to implement the protection for ethaddr
and serial# instead of hard-coding them.

Signed-off-by: Joe Hershberger <joe.hershberger@ni.com>
---
Changes in v4: None
Changes in v3: None
Changes in v2: None

 common/env_flags.c  | 19 -------------------
 include/env_flags.h | 22 ++++++++++++++++++++++
 tools/env/fw_env.c  | 17 -----------------
 3 files changed, 22 insertions(+), 36 deletions(-)

diff --git a/common/env_flags.c b/common/env_flags.c
index 9bf7f2d..8d2a12c 100644
--- a/common/env_flags.c
+++ b/common/env_flags.c
@@ -492,25 +492,6 @@ int env_flags_validate(const ENTRY *item, const char *newval, enum env_op op,
 	/* 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;
diff --git a/include/env_flags.h b/include/env_flags.h
index 0bdae07..d1aa144 100644
--- a/include/env_flags.h
+++ b/include/env_flags.h
@@ -53,7 +53,29 @@ enum env_flags_varaccess {
 #define CONFIG_ENV_FLAGS_LIST_STATIC ""
 #endif
 
+#ifdef CONFIG_CMD_NET
+#ifdef CONFIG_ENV_OVERWRITE
+#define ETHADDR_FLAGS "ethaddr:ma,"
+#else
+#ifdef CONFIG_OVERWRITE_ETHADDR_ONCE
+#define ETHADDR_FLAGS "ethaddr:mc,"
+#else
+#define ETHADDR_FLAGS "ethaddr:mo,"
+#endif
+#endif
+#else
+#define ETHADDR_FLAGS ""
+#endif
+
+#ifndef CONFIG_ENV_OVERWRITE
+#define SERIAL_FLAGS "serial#:so,"
+#else
+#define SERIAL_FLAGS ""
+#endif
+
 #define ENV_FLAGS_LIST_STATIC \
+	ETHADDR_FLAGS \
+	SERIAL_FLAGS \
 	CONFIG_ENV_FLAGS_LIST_STATIC
 
 #ifdef CONFIG_CMD_ENV_FLAGS
diff --git a/tools/env/fw_env.c b/tools/env/fw_env.c
index a596a1b..90c7a5d 100644
--- a/tools/env/fw_env.c
+++ b/tools/env/fw_env.c
@@ -369,23 +369,6 @@ int fw_env_write(char *name, char *value)
 		return 0;
 
 	if (deleting || overwriting) {
-#ifndef CONFIG_ENV_OVERWRITE
-		/*
-		 * Ethernet Address and serial# can be set only once
-		 */
-		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 */
-		   ) ) {
-			fprintf (stderr, "Can't overwrite \"%s\"\n", name);
-			errno = EROFS;
-			return -1;
-		}
-#endif /* CONFIG_ENV_OVERWRITE */
-
 		if (*++nxt == '\0') {
 			*env = '\0';
 		} else {
-- 
1.7.11.5

^ permalink raw reply related	[flat|nested] 124+ messages in thread

* [U-Boot] [PATCH v4 07/20] env: Add support for callbacks to environment vars
  2012-12-05  1:52                                           ` [U-Boot] [PATCH v4 07/20] env: Add support for callbacks to environment vars Joe Hershberger
@ 2012-12-05  2:34                                             ` Graeme Russ
  0 siblings, 0 replies; 124+ messages in thread
From: Graeme Russ @ 2012-12-05  2:34 UTC (permalink / raw)
  To: u-boot

Hi Joe,

What a series! I haven't had a really good look, so I'm having a bit
of trouble getting my head around it all, but this looks very
impressive. I'm almost sorry for the nit I'm about to make...

On Wed, Dec 5, 2012 at 12:52 PM, Joe Hershberger <joe.hershberger@ni.com> wrote:
> Add support for per-variable callbacks to the "hashtable" functions.

> +/*
> + * This list of callback bindings is static, but may be overridden by defining
> + * a new assogiation in the ".callbacks" environment variable.
> + */

association

Regards,

Graeme

^ permalink raw reply	[flat|nested] 124+ messages in thread

* [U-Boot] [PATCH v4 0/20] Add environment call-back and flags capability
  2012-12-05  1:52                                         ` [U-Boot] [PATCH v4 0/20] " Joe Hershberger
                                                             ` (19 preceding siblings ...)
  2012-12-05  1:52                                           ` [U-Boot] [PATCH v4 20/20] env: Handle write-once ethaddr and serial# generically Joe Hershberger
@ 2012-12-11 16:51                                           ` Tom Rini
  2012-12-12  4:16                                           ` [U-Boot] [PATCH v5 " Joe Hershberger
  21 siblings, 0 replies; 124+ messages in thread
From: Tom Rini @ 2012-12-11 16:51 UTC (permalink / raw)
  To: u-boot

On Tue, Dec 04, 2012 at 07:52:27PM -0600, Joe Hershberger wrote:
> 
> When a variable with a registered callback is inserted, deleted, or
> overwritten the callback is called and gives the system an opportunity
> to do something in response to the change.  It also has the opportunuty
> to reject the change by returning non-zero.
> 
> The flags on variables can control their type as well as their allowed
> access.
> 
>         The format of the list is:
>                 type_attribute = [s|d|x|b|i|m]
>                 attributes = type_attribute
>                 entry = variable_name[:attributes]
>                 list = entry[,list]
> 
>         The type attributes are:
>                 s - String (default)
>                 d - Decimal
>                 x - Hexadecimal
>                 b - Boolean ([1yYtT|0nNfF])
>                 i - IP address
>                 m - MAC address
> 
>         The access attributes are:
>                 a - Any (default)
>                 r - Read-only
>                 o - Write-once
>                 c - Change-default
> 
> Changes in v4:
> - Prevent crash on relocation import
> - Fixed help text
> - Add help text for env flags command
> - Add force support to setenv
> - Implement delete

This should fix the problem Wolfgang saw, correct?  And aside from the
comment fix Graeme found, this is ready for merge?  Thanks!

-- 
Tom
-------------- next part --------------
A non-text attachment was scrubbed...
Name: not available
Type: application/pgp-signature
Size: 836 bytes
Desc: Digital signature
URL: <http://lists.denx.de/pipermail/u-boot/attachments/20121211/4c50fd29/attachment.pgp>

^ permalink raw reply	[flat|nested] 124+ messages in thread

* [U-Boot] [PATCH v5 0/20] Add environment call-back and flags capability
  2012-12-05  1:52                                         ` [U-Boot] [PATCH v4 0/20] " Joe Hershberger
                                                             ` (20 preceding siblings ...)
  2012-12-11 16:51                                           ` [U-Boot] [PATCH v4 0/20] Add environment call-back and flags capability Tom Rini
@ 2012-12-12  4:16                                           ` Joe Hershberger
  2012-12-12  4:16                                             ` [U-Boot] [PATCH v5 01/20] Make linux kernel string funcs available to tools Joe Hershberger
                                                               ` (20 more replies)
  21 siblings, 21 replies; 124+ messages in thread
From: Joe Hershberger @ 2012-12-12  4:16 UTC (permalink / raw)
  To: u-boot


When a variable with a registered callback is inserted, deleted, or
overwritten the callback is called and gives the system an opportunity
to do something in response to the change.  It also has the opportunuty
to reject the change by returning non-zero.

The flags on variables can control their type as well as their allowed
access.

        The format of the list is:
                type_attribute = [s|d|x|b|i|m]
                attributes = type_attribute
                entry = variable_name[:attributes]
                list = entry[,list]

        The type attributes are:
                s - String (default)
                d - Decimal
                x - Hexadecimal
                b - Boolean ([1yYtT|0nNfF])
                i - IP address
                m - MAC address

        The access attributes are:
                a - Any (default)
                r - Read-only
                o - Write-once
                c - Change-default

Changes in v5:
- Manually relocate change_ok() pointer
- Add support for CONFIG_NEEDS_MANUAL_RELOC boards
- Fixed comment typo
- Fixed callbacks command help
- Compare current callback against pre-relocation address manually
- Fixed out-of-bounds array access in env_flags_parse_vartype()
- Fixed out-of-bounds array access in env_flags_parse_varaccess()

Changes in v4:
- Prevent crash on relocation import
- Fixed help text
- Add help text for env flags command
- Add force support to setenv
- Implement delete

Changes in v3:
- Rebase onto Gerlando Falauto's env patches
- Refactor himport_r() and hsearch_r()'s parameters
- Split hdelete_r() into the core delete and the validation before
delete
- Delete vars on failed insertion
- Use Marek's linker lists instead of implementing it directly
- Rebase onto latest master
- Add flags parameter to callbacks
- Implement reverse search in env_attr_lookup()
- Fix space skipping in env_attr_lookup()
- All errors coming back from hsearch_r() are no longer fatal.  Don't
abort import on failed ENTER action.
- Removed checkpatch.pl warning

Changes in v2:
- Added much-needed documentation
- Factored out prevch and nextch in env_attr_lookup()

Joe Hershberger (20):
  Make linux kernel string funcs available to tools
  env: Refactor do_apply to a flag
  env: Consolidate common code in hsearch_r()
  env: Refactor apply into change_ok
  env: Use getenv_yesno() more generally
  env: Hide '.' variables in env print by default
  env: Add support for callbacks to environment vars
  env: Add a command to view callbacks
  env: Add a bootfile env handler
  env: Add a baudrate env handler
  env: Add a loadaddr env handler
  env: Add a console env handler
  env: Add a silent env handler
  env: Add environment variable flags
  tools/env: Add environment variable flags support
  env: Add a command to display details about env flags
  env: Add support for access control to .flags
  env: Add setenv force support
  env: Implement the env delete command
  env: Handle write-once ethaddr and serial# generically

 README                          |  80 ++++++
 arch/arm/lib/board.c            |   4 +-
 arch/m68k/lib/board.c           |   3 +-
 arch/microblaze/lib/board.c     |   4 +-
 arch/powerpc/cpu/mpc85xx/mp.c   |   4 +-
 arch/powerpc/lib/board.c        |   9 +-
 arch/sparc/lib/board.c          |   3 +-
 board/Marvell/db64360/db64360.c |  10 +-
 board/Marvell/db64460/db64460.c |  10 +-
 board/esd/cpci750/cpci750.c     |  10 +-
 board/esd/pmc440/cmd_pmc440.c   |   2 +-
 board/gw8260/gw8260.c           |  10 +-
 board/prodrive/p3mx/p3mx.c      |  10 +-
 common/Makefile                 |   6 +
 common/cmd_nvedit.c             | 406 +++++++++++++++++------------
 common/console.c                |  75 +++++-
 common/env_attr.c               | 229 ++++++++++++++++
 common/env_callback.c           | 144 +++++++++++
 common/env_common.c             |  61 +++--
 common/env_dataflash.c          |   2 +-
 common/env_eeprom.c             |   2 +-
 common/env_fat.c                |   2 +-
 common/env_flags.c              | 560 ++++++++++++++++++++++++++++++++++++++++
 common/env_flash.c              |   4 +-
 common/env_mmc.c                |   2 +-
 common/env_nand.c               |   4 +-
 common/env_nvram.c              |   2 +-
 common/env_onenand.c            |   2 +-
 common/env_sf.c                 |   4 +-
 common/image.c                  |  21 +-
 doc/README.silent               |  14 +-
 drivers/serial/serial.c         |  70 +++++
 include/common.h                |   5 +
 include/env_attr.h              |  55 ++++
 include/env_callback.h          |  75 ++++++
 include/env_default.h           |   8 +
 include/env_flags.h             | 172 ++++++++++++
 include/environment.h           |  15 +-
 include/image.h                 |   1 -
 include/linux/linux_string.h    |   8 +
 include/linux/string.h          |   5 +-
 include/search.h                |  37 ++-
 lib/Makefile                    |   1 +
 lib/hashtable.c                 | 244 +++++++++++------
 lib/linux_string.c              |  51 ++++
 lib/string.c                    |  39 ---
 net/net.c                       |  49 ++--
 tools/env/Makefile              |   3 +
 tools/env/fw_env.c              |  92 +++++--
 49 files changed, 2182 insertions(+), 447 deletions(-)
 create mode 100644 common/env_attr.c
 create mode 100644 common/env_callback.c
 create mode 100644 common/env_flags.c
 create mode 100644 include/env_attr.h
 create mode 100644 include/env_callback.h
 create mode 100644 include/env_flags.h
 create mode 100644 include/linux/linux_string.h
 create mode 100644 lib/linux_string.c

-- 
1.7.11.5

^ permalink raw reply	[flat|nested] 124+ messages in thread

* [U-Boot] [PATCH v5 01/20] Make linux kernel string funcs available to tools
  2012-12-12  4:16                                           ` [U-Boot] [PATCH v5 " Joe Hershberger
@ 2012-12-12  4:16                                             ` Joe Hershberger
  2012-12-12  4:16                                             ` [U-Boot] [PATCH v5 02/20] env: Refactor do_apply to a flag Joe Hershberger
                                                               ` (19 subsequent siblings)
  20 siblings, 0 replies; 124+ messages in thread
From: Joe Hershberger @ 2012-12-12  4:16 UTC (permalink / raw)
  To: u-boot

isspace() and strim() are not in the typical user-mode string.h, so
put them in a separate compilation unit so that they can be built into
tools that need them independent of the other common string functions.

This allows code shared by u-boot and the linux user-mode tools to link.

Signed-off-by: Joe Hershberger <joe.hershberger@ni.com>
---
Changes in v5: None
Changes in v4: None
Changes in v3: None
Changes in v2: None

 include/linux/linux_string.h |  8 +++++++
 include/linux/string.h       |  5 +----
 lib/Makefile                 |  1 +
 lib/linux_string.c           | 51 ++++++++++++++++++++++++++++++++++++++++++++
 lib/string.c                 | 39 ---------------------------------
 5 files changed, 61 insertions(+), 43 deletions(-)
 create mode 100644 include/linux/linux_string.h
 create mode 100644 lib/linux_string.c

diff --git a/include/linux/linux_string.h b/include/linux/linux_string.h
new file mode 100644
index 0000000..192b4c9
--- /dev/null
+++ b/include/linux/linux_string.h
@@ -0,0 +1,8 @@
+#ifndef _LINUX_LINUX_STRING_H_
+#define _LINUX_LINUX_STRING_H_
+
+extern char * skip_spaces(const char *);
+
+extern char *strim(char *);
+
+#endif
diff --git a/include/linux/string.h b/include/linux/string.h
index 9a8cbc2..2a6e52f 100644
--- a/include/linux/string.h
+++ b/include/linux/string.h
@@ -47,10 +47,7 @@ extern char * strchr(const char *,int);
 #ifndef __HAVE_ARCH_STRRCHR
 extern char * strrchr(const char *,int);
 #endif
-extern char * skip_spaces(const char *);
-
-extern char *strim(char *);
-
+#include <linux/linux_string.h>
 #ifndef __HAVE_ARCH_STRSTR
 extern char * strstr(const char *,const char *);
 #endif
diff --git a/lib/Makefile b/lib/Makefile
index e44e045..5652986 100644
--- a/lib/Makefile
+++ b/lib/Makefile
@@ -68,6 +68,7 @@ endif
 COBJS-y += crc32.o
 COBJS-y += ctype.o
 COBJS-y += div64.o
+COBJS-y += linux_string.o
 COBJS-y += string.o
 COBJS-y += time.o
 COBJS-$(CONFIG_BOOTP_PXE) += uuid.o
diff --git a/lib/linux_string.c b/lib/linux_string.c
new file mode 100644
index 0000000..d5a5e08
--- /dev/null
+++ b/lib/linux_string.c
@@ -0,0 +1,51 @@
+/*
+ *  linux/lib/string.c
+ *
+ *  Copyright (C) 1991, 1992  Linus Torvalds
+ */
+
+#ifdef USE_HOSTCC
+#include <stdio.h>
+#endif
+
+#include <linux/ctype.h>
+#include <linux/string.h>
+
+/**
+ * skip_spaces - Removes leading whitespace from @str.
+ * @str: The string to be stripped.
+ *
+ * Returns a pointer to the first non-whitespace character in @str.
+ */
+char *skip_spaces(const char *str)
+{
+	while (isspace(*str))
+		++str;
+	return (char *)str;
+}
+
+/**
+ * strim - Removes leading and trailing whitespace from @s.
+ * @s: The string to be stripped.
+ *
+ * Note that the first trailing whitespace is replaced with a %NUL-terminator
+ * in the given string @s. Returns a pointer to the first non-whitespace
+ * character in @s.
+ */
+char *strim(char *s)
+{
+	size_t size;
+	char *end;
+
+	s = skip_spaces(s);
+	size = strlen(s);
+	if (!size)
+		return s;
+
+	end = s + size - 1;
+	while (end >= s && isspace(*end))
+		end--;
+	*(end + 1) = '\0';
+
+	return s;
+}
diff --git a/lib/string.c b/lib/string.c
index c3ad055..2c4f0ec 100644
--- a/lib/string.c
+++ b/lib/string.c
@@ -214,45 +214,6 @@ char * strrchr(const char * s, int c)
 }
 #endif
 
-
-/**
- * skip_spaces - Removes leading whitespace from @str.
- * @str: The string to be stripped.
- *
- * Returns a pointer to the first non-whitespace character in @str.
- */
-char *skip_spaces(const char *str)
-{
-	while (isspace(*str))
-		++str;
-	return (char *)str;
-}
-
-/**
- * strim - Removes leading and trailing whitespace from @s.
- * @s: The string to be stripped.
- *
- * Note that the first trailing whitespace is replaced with a %NUL-terminator
- * in the given string @s. Returns a pointer to the first non-whitespace
- * character in @s.
- */
-char *strim(char *s)
-{
-	size_t size;
-	char *end;
-
-	s = skip_spaces(s);
-	size = strlen(s);
-	if (!size)
-		return s;
-
-	end = s + size - 1;
-	while (end >= s && isspace(*end))
-		end--;
-	*(end + 1) = '\0';
-
-	return s;
-}
 #ifndef __HAVE_ARCH_STRLEN
 /**
  * strlen - Find the length of a string
-- 
1.7.11.5

^ permalink raw reply related	[flat|nested] 124+ messages in thread

* [U-Boot] [PATCH v5 02/20] env: Refactor do_apply to a flag
  2012-12-12  4:16                                           ` [U-Boot] [PATCH v5 " Joe Hershberger
  2012-12-12  4:16                                             ` [U-Boot] [PATCH v5 01/20] Make linux kernel string funcs available to tools Joe Hershberger
@ 2012-12-12  4:16                                             ` Joe Hershberger
  2012-12-12  4:16                                             ` [U-Boot] [PATCH v5 03/20] env: Consolidate common code in hsearch_r() Joe Hershberger
                                                               ` (18 subsequent siblings)
  20 siblings, 0 replies; 124+ messages in thread
From: Joe Hershberger @ 2012-12-12  4:16 UTC (permalink / raw)
  To: u-boot

Use a flag in hsearch_r for insert mode passed from import to allow the
behavior be different based on use.

Now that "do_check" is called for all imports, ensure console init is
complete before updating the console on relocation import

Signed-off-by: Joe Hershberger <joe.hershberger@ni.com>
---
Changes in v5: None
Changes in v4:
- Prevent crash on relocation import

Changes in v3:
- Rebase onto Gerlando Falauto's env patches
- Refactor himport_r() and hsearch_r()'s parameters

Changes in v2: None

 common/cmd_nvedit.c | 19 +++++++++----------
 common/console.c    |  8 ++++----
 common/env_common.c | 26 ++++++++------------------
 include/search.h    | 15 ++++++++-------
 lib/hashtable.c     | 37 ++++++++++++++++++++-----------------
 5 files changed, 49 insertions(+), 56 deletions(-)

diff --git a/common/cmd_nvedit.c b/common/cmd_nvedit.c
index 006131f..a8dc9a6 100644
--- a/common/cmd_nvedit.c
+++ b/common/cmd_nvedit.c
@@ -116,7 +116,7 @@ static int env_print(char *name)
 
 		e.key = name;
 		e.data = NULL;
-		hsearch_r(e, FIND, &ep, &env_htab);
+		hsearch_r(e, FIND, &ep, &env_htab, 0);
 		if (ep == NULL)
 			return 0;
 		len = printf("%s=%s\n", ep->key, ep->data);
@@ -224,7 +224,7 @@ int env_check_apply(const char *name, const char *oldval,
 	else if (strcmp(name, "stderr") == 0)
 		console = stderr;
 
-	if (console != -1) {
+	if (console != -1 && (gd->flags & GD_FLG_DEVINIT) != 0) {
 		if ((newval == NULL) || (*newval == '\0')) {
 			/* We cannot delete stdin/stdout/stderr */
 			if ((flag & H_FORCE) == 0)
@@ -344,20 +344,19 @@ static int _do_env_set(int flag, int argc, char * const argv[])
 	 */
 	e.key = name;
 	e.data = NULL;
-	hsearch_r(e, FIND, &ep, &env_htab);
+	hsearch_r(e, FIND, &ep, &env_htab, 0);
 
 	/*
-	 * Perform requested checks. Notice how since we are overwriting
-	 * a single variable, we need to set H_NOCLEAR
+	 * Perform requested checks.
 	 */
-	if (env_check_apply(name, ep ? ep->data : NULL, value, H_NOCLEAR)) {
+	if (env_check_apply(name, ep ? ep->data : NULL, value, 0)) {
 		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, 0);
+		int rc = hdelete_r(name, &env_htab, H_INTERACTIVE);
 		return !rc;
 	}
 
@@ -384,7 +383,7 @@ static int _do_env_set(int flag, int argc, char * const argv[])
 
 	e.key	= name;
 	e.data	= value;
-	hsearch_r(e, ENTER, &ep, &env_htab);
+	hsearch_r(e, ENTER, &ep, &env_htab, H_INTERACTIVE);
 	free(value);
 	if (!ep) {
 		printf("## Error inserting \"%s\" variable, errno=%d\n",
@@ -552,7 +551,7 @@ char *getenv(const char *name)
 
 		e.key	= name;
 		e.data	= NULL;
-		hsearch_r(e, FIND, &ep, &env_htab);
+		hsearch_r(e, FIND, &ep, &env_htab, 0);
 
 		return ep ? ep->data : NULL;
 	}
@@ -951,7 +950,7 @@ static int do_env_import(cmd_tbl_t *cmdtp, int flag,
 	}
 
 	if (himport_r(&env_htab, addr, size, sep, del ? 0 : H_NOCLEAR,
-			0, NULL, 0 /* do_apply */) == 0) {
+			0, NULL) == 0) {
 		error("Environment import failed: errno = %d\n", errno);
 		return 1;
 	}
diff --git a/common/console.c b/common/console.c
index 1177f7d..880acd9 100644
--- a/common/console.c
+++ b/common/console.c
@@ -683,8 +683,6 @@ int console_init_r(void)
 done:
 #endif
 
-	gd->flags |= GD_FLG_DEVINIT;	/* device initialization completed */
-
 	stdio_print_current_devices();
 
 #ifdef CONFIG_SYS_CONSOLE_ENV_OVERWRITE
@@ -694,6 +692,8 @@ done:
 	}
 #endif /* CONFIG_SYS_CONSOLE_ENV_OVERWRITE */
 
+	gd->flags |= GD_FLG_DEVINIT;	/* device initialization completed */
+
 #if 0
 	/* If nothing usable installed, use only the initial console */
 	if ((stdio_devices[stdin] == NULL) && (stdio_devices[stdout] == NULL))
@@ -758,8 +758,6 @@ int console_init_r(void)
 #endif
 	}
 
-	gd->flags |= GD_FLG_DEVINIT;	/* device initialization completed */
-
 	stdio_print_current_devices();
 
 	/* Setting environment variables */
@@ -767,6 +765,8 @@ int console_init_r(void)
 		setenv(stdio_names[i], stdio_devices[i]->name);
 	}
 
+	gd->flags |= GD_FLG_DEVINIT;	/* device initialization completed */
+
 #if 0
 	/* If nothing usable installed, use only the initial console */
 	if ((stdio_devices[stdin] == NULL) && (stdio_devices[stdout] == NULL))
diff --git a/common/env_common.c b/common/env_common.c
index 3d3cb70..f22f5b9 100644
--- a/common/env_common.c
+++ b/common/env_common.c
@@ -83,11 +83,8 @@ 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
-	 */
-	int do_apply = 0;
+	int flags = 0;
+
 	if (sizeof(default_environment) > ENV_SIZE) {
 		puts("*** Error - default environment is too large\n\n");
 		return;
@@ -99,14 +96,7 @@ 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 check every single
-			 * variable and apply changes to the system
-			 * right away (e.g. baudrate, console).
-			 */
-			do_apply = 1;
+			flags = H_INTERACTIVE;
 			puts(s);
 		}
 	} else {
@@ -114,8 +104,8 @@ void set_default_env(const char *s)
 	}
 
 	if (himport_r(&env_htab, (char *)default_environment,
-			sizeof(default_environment), '\0', 0,
-			0, NULL, do_apply) == 0)
+			sizeof(default_environment), '\0', flags,
+			0, NULL) == 0)
 		error("Environment import failed: errno = %d\n", errno);
 
 	gd->flags |= GD_FLG_ENV_READY;
@@ -130,8 +120,8 @@ int set_default_vars(int nvars, char * const vars[])
 	 * (and use \0 as a separator)
 	 */
 	return himport_r(&env_htab, (const char *)default_environment,
-				sizeof(default_environment), '\0', H_NOCLEAR,
-				nvars, vars, 1 /* do_apply */);
+				sizeof(default_environment), '\0',
+				H_NOCLEAR | H_INTERACTIVE, nvars, vars);
 }
 
 #ifndef CONFIG_SPL_BUILD
@@ -155,7 +145,7 @@ int env_import(const char *buf, int check)
 	}
 
 	if (himport_r(&env_htab, (char *)ep->data, ENV_SIZE, '\0', 0,
-			0, NULL, 0 /* do_apply */)) {
+			0, NULL)) {
 		gd->flags |= GD_FLG_ENV_READY;
 		return 1;
 	}
diff --git a/include/search.h b/include/search.h
index 93e1cbc..f5165b0 100644
--- a/include/search.h
+++ b/include/search.h
@@ -73,7 +73,7 @@ struct hsearch_data {
 extern int hcreate_r(size_t __nel, struct hsearch_data *__htab);
 
 /* Destroy current internal hashing table.  */
-extern void hdestroy_r(struct hsearch_data *__htab, int do_apply);
+extern void hdestroy_r(struct hsearch_data *__htab);
 
 /*
  * Search for entry matching ITEM.key in internal hash table.  If
@@ -82,7 +82,7 @@ extern void hdestroy_r(struct hsearch_data *__htab, int do_apply);
  * ITEM.data.
  * */
 extern int hsearch_r(ENTRY __item, ACTION __action, ENTRY ** __retval,
-		     struct hsearch_data *__htab);
+		     struct hsearch_data *__htab, int __flag);
 
 /*
  * Search for an entry matching `MATCH'.  Otherwise, Same semantics
@@ -99,7 +99,7 @@ extern int hstrstr_r(const char *__match, int __last_idx, ENTRY ** __retval,
 
 /* Search and delete entry matching ITEM.key in internal hash table. */
 extern int hdelete_r(const char *__key, struct hsearch_data *__htab,
-			int do_apply);
+		     int __flag);
 
 extern ssize_t hexport_r(struct hsearch_data *__htab,
 		     const char __sep, char **__resp, size_t __size,
@@ -113,10 +113,11 @@ extern ssize_t hexport_r(struct hsearch_data *__htab,
  */
 extern int himport_r(struct hsearch_data *__htab,
 		     const char *__env, size_t __size, const char __sep,
-		     int __flag, int nvars, char * const vars[], int do_apply);
+		     int __flag, int nvars, char * const vars[]);
 
-/* Flags for himport_r() */
-#define	H_NOCLEAR	(1 << 0) /* do not clear hash table before importing */
-#define	H_FORCE		(1 << 1) /* overwrite read-only/write-once variables */
+/* Flags for himport_r(), hdelete_r(), and hsearch_r() */
+#define H_NOCLEAR	(1 << 0) /* do not clear hash table before importing */
+#define H_FORCE		(1 << 1) /* overwrite read-only/write-once variables */
+#define H_INTERACTIVE	(1 << 2) /* indicate that an import is user directed */
 
 #endif /* search.h */
diff --git a/lib/hashtable.c b/lib/hashtable.c
index 94a7b61..f0056ac 100644
--- a/lib/hashtable.c
+++ b/lib/hashtable.c
@@ -142,7 +142,7 @@ int hcreate_r(size_t nel, struct hsearch_data *htab)
  * be freed and the local static variable can be marked as not used.
  */
 
-void hdestroy_r(struct hsearch_data *htab, int do_apply)
+void hdestroy_r(struct hsearch_data *htab)
 {
 	int i;
 
@@ -156,10 +156,7 @@ void hdestroy_r(struct hsearch_data *htab, int do_apply)
 	for (i = 1; i <= htab->size; ++i) {
 		if (htab->table[i].used > 0) {
 			ENTRY *ep = &htab->table[i].entry;
-			if (do_apply && htab->apply != NULL) {
-				/* deletion is always forced */
-				htab->apply(ep->key, ep->data, NULL, H_FORCE);
-			}
+
 			free((void *)ep->key);
 			free(ep->data);
 		}
@@ -251,7 +248,7 @@ int hmatch_r(const char *match, int last_idx, ENTRY ** retval,
 }
 
 int hsearch_r(ENTRY item, ACTION action, ENTRY ** retval,
-	      struct hsearch_data *htab)
+	      struct hsearch_data *htab, int flag)
 {
 	unsigned int hval;
 	unsigned int count;
@@ -404,7 +401,7 @@ int hsearch_r(ENTRY item, ACTION action, ENTRY ** retval,
  * do that.
  */
 
-int hdelete_r(const char *key, struct hsearch_data *htab, int do_apply)
+int hdelete_r(const char *key, struct hsearch_data *htab, int flag)
 {
 	ENTRY e, *ep;
 	int idx;
@@ -413,15 +410,21 @@ int hdelete_r(const char *key, struct hsearch_data *htab, int do_apply)
 
 	e.key = (char *)key;
 
-	if ((idx = hsearch_r(e, FIND, &ep, htab)) == 0) {
+	idx = hsearch_r(e, FIND, &ep, htab, 0);
+	if (idx == 0) {
 		__set_errno(ESRCH);
 		return 0;	/* not found */
 	}
 
+	/* Check for permission */
+	if (htab->apply != NULL &&
+	    htab->apply(ep->key, ep->data, NULL, flag)) {
+		__set_errno(EPERM);
+		return 0;
+	}
+
 	/* free used ENTRY */
 	debug("hdelete: DELETING key \"%s\"\n", key);
-	if (do_apply && htab->apply != NULL)
-		htab->apply(ep->key, ep->data, NULL, H_FORCE);
 	free((void *)ep->key);
 	free(ep->data);
 	htab->table[idx].used = -1;
@@ -674,7 +677,7 @@ static int drop_var_from_set(const char *name, int nvars, char * vars[])
 
 int himport_r(struct hsearch_data *htab,
 		const char *env, size_t size, const char sep, int flag,
-		int nvars, char * const vars[], int do_apply)
+		int nvars, char * const vars[])
 {
 	char *data, *sp, *dp, *name, *value;
 	char *localvars[nvars];
@@ -704,7 +707,7 @@ int himport_r(struct hsearch_data *htab,
 		debug("Destroy Hash Table: %p table = %p\n", htab,
 		       htab->table);
 		if (htab->table)
-			hdestroy_r(htab, do_apply);
+			hdestroy_r(htab);
 	}
 
 	/*
@@ -770,7 +773,7 @@ int himport_r(struct hsearch_data *htab,
 			if (!drop_var_from_set(name, nvars, localvars))
 				continue;
 
-			if (hdelete_r(name, htab, do_apply) == 0)
+			if (hdelete_r(name, htab, flag) == 0)
 				debug("DELETE ERROR ##############################\n");
 
 			continue;
@@ -795,14 +798,14 @@ int himport_r(struct hsearch_data *htab,
 		e.data = value;
 
 		/* if there is an apply function, check what it has to say */
-		if (do_apply && htab->apply != NULL) {
+		if (htab->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);
+			hsearch_r(e, FIND, &rv, htab, 0);
 			debug("previous value was %s\n", rv ? rv->data : "");
 			if (htab->apply(name, rv ? rv->data : NULL,
 				value, flag)) {
@@ -812,7 +815,7 @@ int himport_r(struct hsearch_data *htab,
 			}
 		}
 
-		hsearch_r(e, ENTER, &rv, htab);
+		hsearch_r(e, ENTER, &rv, htab, flag);
 		if (rv == NULL) {
 			printf("himport_r: can't insert \"%s=%s\" into hash table\n",
 				name, value);
@@ -839,7 +842,7 @@ int himport_r(struct hsearch_data *htab,
 		 * b) if the variable was not present in current env, we notify
 		 *    it might be a typo
 		 */
-		if (hdelete_r(localvars[i], htab, do_apply) == 0)
+		if (hdelete_r(localvars[i], htab, flag) == 0)
 			printf("WARNING: '%s' neither in running nor in imported env!\n", localvars[i]);
 		else
 			printf("WARNING: '%s' not in imported env, deleting it!\n", localvars[i]);
-- 
1.7.11.5

^ permalink raw reply related	[flat|nested] 124+ messages in thread

* [U-Boot] [PATCH v5 03/20] env: Consolidate common code in hsearch_r()
  2012-12-12  4:16                                           ` [U-Boot] [PATCH v5 " Joe Hershberger
  2012-12-12  4:16                                             ` [U-Boot] [PATCH v5 01/20] Make linux kernel string funcs available to tools Joe Hershberger
  2012-12-12  4:16                                             ` [U-Boot] [PATCH v5 02/20] env: Refactor do_apply to a flag Joe Hershberger
@ 2012-12-12  4:16                                             ` Joe Hershberger
  2012-12-12  4:16                                             ` [U-Boot] [PATCH v5 04/20] env: Refactor apply into change_ok Joe Hershberger
                                                               ` (17 subsequent siblings)
  20 siblings, 0 replies; 124+ messages in thread
From: Joe Hershberger @ 2012-12-12  4:16 UTC (permalink / raw)
  To: u-boot

The same chunk of code was replicated in two places and the following
changes will make that chunk grow a bit, so combine into a static func.

Signed-off-by: Joe Hershberger <joe.hershberger@ni.com>
---
Changes in v5: None
Changes in v4: None
Changes in v3: None
Changes in v2: None

 lib/hashtable.c | 71 ++++++++++++++++++++++++++++++---------------------------
 1 file changed, 37 insertions(+), 34 deletions(-)

diff --git a/lib/hashtable.c b/lib/hashtable.c
index f0056ac..f4d5795 100644
--- a/lib/hashtable.c
+++ b/lib/hashtable.c
@@ -247,6 +247,34 @@ int hmatch_r(const char *match, int last_idx, ENTRY ** retval,
 	return 0;
 }
 
+/*
+ * Compare an existing entry with the desired key, and overwrite if the action
+ * is ENTER.  This is simply a helper function for hsearch_r().
+ */
+static inline int _compare_and_overwrite_entry(ENTRY item, ACTION action,
+	ENTRY **retval, struct hsearch_data *htab, int flag,
+	unsigned int hval, unsigned int idx)
+{
+	if (htab->table[idx].used == hval
+	    && strcmp(item.key, htab->table[idx].entry.key) == 0) {
+		/* Overwrite existing value? */
+		if ((action == ENTER) && (item.data != NULL)) {
+			free(htab->table[idx].entry.data);
+			htab->table[idx].entry.data = strdup(item.data);
+			if (!htab->table[idx].entry.data) {
+				__set_errno(ENOMEM);
+				*retval = NULL;
+				return 0;
+			}
+		}
+		/* return found entry */
+		*retval = &htab->table[idx].entry;
+		return idx;
+	}
+	/* keep searching */
+	return -1;
+}
+
 int hsearch_r(ENTRY item, ACTION action, ENTRY ** retval,
 	      struct hsearch_data *htab, int flag)
 {
@@ -255,6 +283,7 @@ int hsearch_r(ENTRY item, ACTION action, ENTRY ** retval,
 	unsigned int len = strlen(item.key);
 	unsigned int idx;
 	unsigned int first_deleted = 0;
+	int ret;
 
 	/* Compute an value for the given string. Perhaps use a better method. */
 	hval = len;
@@ -286,23 +315,10 @@ int hsearch_r(ENTRY item, ACTION action, ENTRY ** retval,
 		    && !first_deleted)
 			first_deleted = idx;
 
-		if (htab->table[idx].used == hval
-		    && strcmp(item.key, htab->table[idx].entry.key) == 0) {
-			/* Overwrite existing value? */
-			if ((action == ENTER) && (item.data != NULL)) {
-				free(htab->table[idx].entry.data);
-				htab->table[idx].entry.data =
-					strdup(item.data);
-				if (!htab->table[idx].entry.data) {
-					__set_errno(ENOMEM);
-					*retval = NULL;
-					return 0;
-				}
-			}
-			/* return found entry */
-			*retval = &htab->table[idx].entry;
-			return idx;
-		}
+		ret = _compare_and_overwrite_entry(item, action, retval, htab,
+			flag, hval, idx);
+		if (ret != -1)
+			return ret;
 
 		/*
 		 * Second hash function:
@@ -328,23 +344,10 @@ int hsearch_r(ENTRY item, ACTION action, ENTRY ** retval,
 				break;
 
 			/* If entry is found use it. */
-			if ((htab->table[idx].used == hval)
-			    && strcmp(item.key, htab->table[idx].entry.key) == 0) {
-				/* Overwrite existing value? */
-				if ((action == ENTER) && (item.data != NULL)) {
-					free(htab->table[idx].entry.data);
-					htab->table[idx].entry.data =
-						strdup(item.data);
-					if (!htab->table[idx].entry.data) {
-						__set_errno(ENOMEM);
-						*retval = NULL;
-						return 0;
-					}
-				}
-				/* return found entry */
-				*retval = &htab->table[idx].entry;
-				return idx;
-			}
+			ret = _compare_and_overwrite_entry(item, action, retval,
+				htab, flag, hval, idx);
+			if (ret != -1)
+				return ret;
 		}
 		while (htab->table[idx].used);
 	}
-- 
1.7.11.5

^ permalink raw reply related	[flat|nested] 124+ messages in thread

* [U-Boot] [PATCH v5 04/20] env: Refactor apply into change_ok
  2012-12-12  4:16                                           ` [U-Boot] [PATCH v5 " Joe Hershberger
                                                               ` (2 preceding siblings ...)
  2012-12-12  4:16                                             ` [U-Boot] [PATCH v5 03/20] env: Consolidate common code in hsearch_r() Joe Hershberger
@ 2012-12-12  4:16                                             ` Joe Hershberger
  2012-12-12  4:16                                             ` [U-Boot] [PATCH v5 05/20] env: Use getenv_yesno() more generally Joe Hershberger
                                                               ` (16 subsequent siblings)
  20 siblings, 0 replies; 124+ messages in thread
From: Joe Hershberger @ 2012-12-12  4:16 UTC (permalink / raw)
  To: u-boot

Move the read of the old value to inside the check function.  In some
cases it can be avoided all together and at the least the code is only
called from one place.

Also name the function and the callback to more clearly describe what
it does.

Pass the ENTRY instead of just the name for direct access to the whole
data structure.

Pass an enum to the callback that specifies the operation being approved.

Signed-off-by: Joe Hershberger <joe.hershberger@ni.com>
---
Changes in v5:
- Manually relocate change_ok() pointer

Changes in v4: None
Changes in v3:
- Split hdelete_r() into the core delete and the validation before
delete
- Delete vars on failed insertion

Changes in v2: None

 common/cmd_nvedit.c   | 34 +++++++++++--------------
 common/env_common.c   |  3 ++-
 include/environment.h |  7 +++---
 include/search.h      | 13 +++++++---
 lib/hashtable.c       | 70 +++++++++++++++++++++++++++++++--------------------
 5 files changed, 72 insertions(+), 55 deletions(-)

diff --git a/common/cmd_nvedit.c b/common/cmd_nvedit.c
index a8dc9a6..da5689c 100644
--- a/common/cmd_nvedit.c
+++ b/common/cmd_nvedit.c
@@ -208,10 +208,20 @@ static int do_env_grep(cmd_tbl_t *cmdtp, int flag,
  * overwriting of write-once variables.
  */
 
-int env_check_apply(const char *name, const char *oldval,
-			const char *newval, int flag)
+int env_change_ok(const ENTRY *item, const char *newval, enum env_op op,
+	int flag)
 {
 	int   console = -1;
+	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 ? : "";
@@ -242,12 +252,12 @@ int env_check_apply(const char *name, const char *oldval,
 #endif /* CONFIG_CONSOLE_MUX */
 	}
 
+#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.
 	 */
-#ifndef CONFIG_ENV_OVERWRITE
-	if (oldval != NULL &&			/* variable exists */
+	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
@@ -265,7 +275,7 @@ int env_check_apply(const char *name, const char *oldval,
 	 * (which will erase all variables prior to calling this),
 	 * we want the baudrate to actually change - for real.
 	 */
-	if (oldval != NULL ||			/* variable exists */
+	if (op != env_op_create ||		/* variable exists */
 		(flag & H_NOCLEAR) == 0) {	/* or env is clear */
 		/*
 		 * Switch to new baudrate if new baudrate is supported
@@ -339,20 +349,6 @@ static int _do_env_set(int flag, int argc, char * const argv[])
 	}
 
 	env_id++;
-	/*
-	 * search if variable with this name already exists
-	 */
-	e.key = name;
-	e.data = NULL;
-	hsearch_r(e, FIND, &ep, &env_htab, 0);
-
-	/*
-	 * Perform requested checks.
-	 */
-	if (env_check_apply(name, ep ? ep->data : NULL, value, 0)) {
-		debug("check function did not approve, refusing\n");
-		return 1;
-	}
 
 	/* Delete only ? */
 	if (argc < 3 || argv[2] == NULL) {
diff --git a/common/env_common.c b/common/env_common.c
index f22f5b9..a960aa8 100644
--- a/common/env_common.c
+++ b/common/env_common.c
@@ -40,7 +40,7 @@ DECLARE_GLOBAL_DATA_PTR;
 #include <env_default.h>
 
 struct hsearch_data env_htab = {
-	.apply = env_check_apply,
+	.change_ok = env_change_ok,
 };
 
 static uchar __env_get_char_spec(int index)
@@ -162,6 +162,7 @@ void env_relocate(void)
 {
 #if defined(CONFIG_NEEDS_MANUAL_RELOC)
 	env_reloc();
+	env_htab.change_ok += gd->reloc_off;
 #endif
 	if (gd->env_valid == 0) {
 #if defined(CONFIG_ENV_IS_NOWHERE) || defined(CONFIG_SPL_BUILD)
diff --git a/include/environment.h b/include/environment.h
index e8ab703..4b19f32 100644
--- a/include/environment.h
+++ b/include/environment.h
@@ -188,13 +188,12 @@ int set_default_vars(int nvars, char * const vars[]);
 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).
+ * Check if variable "item" can be changed to newval
  * When (flag & H_FORCE) is set, it does not print out any error
  * message and forces overwriting of write-once variables.
  */
-int env_check_apply(const char *name, const char *oldval,
-			const char *newval, int flag);
+int env_change_ok(const ENTRY *item, const char *newval, enum env_op op,
+	int flag);
 
 #endif /* DO_DEPS_ONLY */
 
diff --git a/include/search.h b/include/search.h
index f5165b0..fa00ea1 100644
--- a/include/search.h
+++ b/include/search.h
@@ -32,6 +32,12 @@
 
 #define __set_errno(val) do { errno = val; } while (0)
 
+enum env_op {
+	env_op_create,
+	env_op_delete,
+	env_op_overwrite,
+};
+
 /* Action which shall be performed in the call the hsearch.  */
 typedef enum {
 	FIND,
@@ -59,14 +65,13 @@ struct hsearch_data {
 	unsigned int filled;
 /*
  * Callback function which will check whether the given change for variable
- * "name" from "oldval" to "newval" may be applied or not, and possibly apply
- * such change.
+ * "item" to "newval" may be applied or not, and possibly apply such change.
  * When (flag & H_FORCE) is set, it shall not print out any error message and
  * shall force overwriting of write-once variables.
 .* Must return 0 for approval, 1 for denial.
  */
-	int (*apply)(const char *name, const char *oldval,
-			const char *newval, int flag);
+	int (*change_ok)(const ENTRY *__item, const char *newval, enum env_op,
+		int flag);
 };
 
 /* Create a new hashing table which will at most contain NEL elements.  */
diff --git a/lib/hashtable.c b/lib/hashtable.c
index f4d5795..6861a42 100644
--- a/lib/hashtable.c
+++ b/lib/hashtable.c
@@ -66,12 +66,16 @@
  * Instead the interface of all functions is extended to take an argument
  * which describes the current status.
  */
+
 typedef struct _ENTRY {
 	int used;
 	ENTRY entry;
 } _ENTRY;
 
 
+static void _hdelete(const char *key, struct hsearch_data *htab, ENTRY *ep,
+	int idx);
+
 /*
  * hcreate()
  */
@@ -259,6 +263,17 @@ static inline int _compare_and_overwrite_entry(ENTRY item, ACTION action,
 	    && strcmp(item.key, htab->table[idx].entry.key) == 0) {
 		/* Overwrite existing value? */
 		if ((action == ENTER) && (item.data != NULL)) {
+			/* check for permission */
+			if (htab->change_ok != NULL && htab->change_ok(
+			    &htab->table[idx].entry, item.data,
+			    env_op_overwrite, flag)) {
+				debug("change_ok() rejected setting variable "
+					"%s, skipping it!\n", item.key);
+				__set_errno(EPERM);
+				*retval = NULL;
+				return 0;
+			}
+
 			free(htab->table[idx].entry.data);
 			htab->table[idx].entry.data = strdup(item.data);
 			if (!htab->table[idx].entry.data) {
@@ -383,6 +398,17 @@ int hsearch_r(ENTRY item, ACTION action, ENTRY ** retval,
 
 		++htab->filled;
 
+		/* check for permission */
+		if (htab->change_ok != NULL && htab->change_ok(
+		    &htab->table[idx].entry, item.data, env_op_create, flag)) {
+			debug("change_ok() rejected setting variable "
+				"%s, skipping it!\n", item.key);
+			_hdelete(item.key, htab, &htab->table[idx].entry, idx);
+			__set_errno(EPERM);
+			*retval = NULL;
+			return 0;
+		}
+
 		/* return new entry */
 		*retval = &htab->table[idx].entry;
 		return 1;
@@ -404,6 +430,18 @@ int hsearch_r(ENTRY item, ACTION action, ENTRY ** retval,
  * do that.
  */
 
+static void _hdelete(const char *key, struct hsearch_data *htab, ENTRY *ep,
+	int idx)
+{
+	/* free used ENTRY */
+	debug("hdelete: DELETING key \"%s\"\n", key);
+	free((void *)ep->key);
+	free(ep->data);
+	htab->table[idx].used = -1;
+
+	--htab->filled;
+}
+
 int hdelete_r(const char *key, struct hsearch_data *htab, int flag)
 {
 	ENTRY e, *ep;
@@ -420,19 +458,15 @@ int hdelete_r(const char *key, struct hsearch_data *htab, int flag)
 	}
 
 	/* Check for permission */
-	if (htab->apply != NULL &&
-	    htab->apply(ep->key, ep->data, NULL, flag)) {
+	if (htab->change_ok != NULL &&
+	    htab->change_ok(ep, NULL, env_op_delete, flag)) {
+		debug("change_ok() rejected deleting variable "
+			"%s, skipping it!\n", key);
 		__set_errno(EPERM);
 		return 0;
 	}
 
-	/* free used ENTRY */
-	debug("hdelete: DELETING key \"%s\"\n", key);
-	free((void *)ep->key);
-	free(ep->data);
-	htab->table[idx].used = -1;
-
-	--htab->filled;
+	_hdelete(key, htab, ep, idx);
 
 	return 1;
 }
@@ -800,24 +834,6 @@ int himport_r(struct hsearch_data *htab,
 		e.key = name;
 		e.data = value;
 
-		/* if there is an apply function, check what it has to say */
-		if (htab->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, 0);
-			debug("previous value was %s\n", rv ? rv->data : "");
-			if (htab->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, flag);
 		if (rv == NULL) {
 			printf("himport_r: can't insert \"%s=%s\" into hash table\n",
-- 
1.7.11.5

^ permalink raw reply related	[flat|nested] 124+ messages in thread

* [U-Boot] [PATCH v5 05/20] env: Use getenv_yesno() more generally
  2012-12-12  4:16                                           ` [U-Boot] [PATCH v5 " Joe Hershberger
                                                               ` (3 preceding siblings ...)
  2012-12-12  4:16                                             ` [U-Boot] [PATCH v5 04/20] env: Refactor apply into change_ok Joe Hershberger
@ 2012-12-12  4:16                                             ` Joe Hershberger
  2012-12-12  4:16                                             ` [U-Boot] [PATCH v5 06/20] env: Hide '.' variables in env print by default Joe Hershberger
                                                               ` (15 subsequent siblings)
  20 siblings, 0 replies; 124+ messages in thread
From: Joe Hershberger @ 2012-12-12  4:16 UTC (permalink / raw)
  To: u-boot

Move the getenv_yesno() to env_common.c and change most checks for
'y' or 'n' to use this helper.

Signed-off-by: Joe Hershberger <joe.hershberger@ni.com>
---
Changes in v5: None
Changes in v4: None
Changes in v3: None
Changes in v2: None

 arch/arm/lib/board.c            |  4 +---
 arch/m68k/lib/board.c           |  3 +--
 arch/microblaze/lib/board.c     |  4 +---
 arch/powerpc/cpu/mpc85xx/mp.c   |  4 +---
 arch/powerpc/lib/board.c        |  9 ++-------
 arch/sparc/lib/board.c          |  3 +--
 board/Marvell/db64360/db64360.c | 10 +++-------
 board/Marvell/db64460/db64460.c | 10 +++-------
 board/esd/cpci750/cpci750.c     | 10 +++-------
 board/gw8260/gw8260.c           | 10 +++-------
 board/prodrive/p3mx/p3mx.c      | 10 +++-------
 common/env_common.c             | 14 ++++++++++++++
 common/image.c                  |  6 ------
 include/common.h                |  5 +++++
 include/image.h                 |  1 -
 net/net.c                       | 32 +++++++++++++++-----------------
 16 files changed, 56 insertions(+), 79 deletions(-)

diff --git a/arch/arm/lib/board.c b/arch/arm/lib/board.c
index 22a4d9c..e0cb635 100644
--- a/arch/arm/lib/board.c
+++ b/arch/arm/lib/board.c
@@ -540,15 +540,13 @@ void board_init_r(gd_t *id, ulong dest_addr)
 	flash_size = flash_init();
 	if (flash_size > 0) {
 # ifdef CONFIG_SYS_FLASH_CHECKSUM
-		char *s = getenv("flashchecksum");
-
 		print_size(flash_size, "");
 		/*
 		 * Compute and print flash CRC if flashchecksum is set to 'y'
 		 *
 		 * NOTE: Maybe we should add some WATCHDOG_RESET()? XXX
 		 */
-		if (s && (*s == 'y')) {
+		if (getenv_yesno("flashchecksum") == 1) {
 			printf("  CRC: %08X", crc32(0,
 				(const unsigned char *) CONFIG_SYS_FLASH_BASE,
 				flash_size));
diff --git a/arch/m68k/lib/board.c b/arch/m68k/lib/board.c
index 02d73fd..794b867 100644
--- a/arch/m68k/lib/board.c
+++ b/arch/m68k/lib/board.c
@@ -462,8 +462,7 @@ void board_init_r (gd_t *id, ulong dest_addr)
 		 *
 		 * NOTE: Maybe we should add some WATCHDOG_RESET()? XXX
 		 */
-		s = getenv ("flashchecksum");
-		if (s && (*s == 'y')) {
+		if (getenv_yesno("flashchecksum") == 1) {
 			printf ("  CRC: %08X",
 					crc32 (0,
 						   (const unsigned char *) CONFIG_SYS_FLASH_BASE,
diff --git a/arch/microblaze/lib/board.c b/arch/microblaze/lib/board.c
index efd63cd..a7c2f76 100644
--- a/arch/microblaze/lib/board.c
+++ b/arch/microblaze/lib/board.c
@@ -74,7 +74,6 @@ void board_init_f(ulong not_used)
 	gd = (gd_t *) (CONFIG_SYS_SDRAM_BASE + CONFIG_SYS_GBL_DATA_OFFSET);
 	bd = (bd_t *) (CONFIG_SYS_SDRAM_BASE + CONFIG_SYS_GBL_DATA_OFFSET \
 						- GENERATED_BD_INFO_SIZE);
-	__maybe_unused char *s;
 #if defined(CONFIG_CMD_FLASH)
 	ulong flash_size = 0;
 #endif
@@ -143,8 +142,7 @@ void board_init_f(ulong not_used)
 		 *
 		 * NOTE: Maybe we should add some WATCHDOG_RESET()? XXX
 		 */
-		s = getenv ("flashchecksum");
-		if (s && (*s == 'y')) {
+		if (getenv_yesno("flashchecksum") == 1) {
 			printf ("  CRC: %08X",
 				crc32(0, (const u8 *)bd->bi_flashstart,
 							flash_size)
diff --git a/arch/powerpc/cpu/mpc85xx/mp.c b/arch/powerpc/cpu/mpc85xx/mp.c
index e1197ac..43d4836 100644
--- a/arch/powerpc/cpu/mpc85xx/mp.c
+++ b/arch/powerpc/cpu/mpc85xx/mp.c
@@ -46,10 +46,8 @@ u32 get_my_id()
  */
 int hold_cores_in_reset(int verbose)
 {
-	const char *s = getenv("mp_holdoff");
-
 	/* Default to no, overriden by 'y', 'yes', 'Y', 'Yes', or '1' */
-	if (s && (*s == 'y' || *s == 'Y' || *s == '1')) {
+	if (getenv_yesno("mp_holdoff") == 1) {
 		if (verbose) {
 			puts("Secondary cores are being held in reset.\n");
 			puts("See 'mp_holdoff' environment variable\n");
diff --git a/arch/powerpc/lib/board.c b/arch/powerpc/lib/board.c
index 1b051e1..6a7bf4b 100644
--- a/arch/powerpc/lib/board.c
+++ b/arch/powerpc/lib/board.c
@@ -739,16 +739,13 @@ void board_init_r(gd_t *id, ulong dest_addr)
 		flash_size = 0;
 	} else if ((flash_size = flash_init()) > 0) {
 #ifdef CONFIG_SYS_FLASH_CHECKSUM
-		char *s;
-
 		print_size(flash_size, "");
 		/*
 		 * Compute and print flash CRC if flashchecksum is set to 'y'
 		 *
 		 * NOTE: Maybe we should add some WATCHDOG_RESET()? XXX
 		 */
-		s = getenv("flashchecksum");
-		if (s && (*s == 'y')) {
+		if (getenv_yesno("flashchecksum") == 1) {
 			printf("  CRC: %08X",
 			       crc32(0,
 				     (const unsigned char *)
@@ -841,9 +838,7 @@ void board_init_r(gd_t *id, ulong dest_addr)
 	 * "i2cfast" into account
 	 */
 	{
-		char *s = getenv("i2cfast");
-
-		if (s && ((*s == 'y') || (*s == 'Y'))) {
+		if (getenv_yesno("i2cfast") == 1) {
 			bd->bi_iic_fast[0] = 1;
 			bd->bi_iic_fast[1] = 1;
 		}
diff --git a/arch/sparc/lib/board.c b/arch/sparc/lib/board.c
index 32d025a..1b5e995 100644
--- a/arch/sparc/lib/board.c
+++ b/arch/sparc/lib/board.c
@@ -284,8 +284,7 @@ void board_init_f(ulong bootflag)
 		 *
 		 * NOTE: Maybe we should add some WATCHDOG_RESET()? XXX
 		 */
-		s = getenv("flashchecksum");
-		if (s && (*s == 'y')) {
+		if (getenv_yesno("flashchecksum") == 1) {
 			printf("  CRC: %08lX",
 			       crc32(0, (const unsigned char *)CONFIG_SYS_FLASH_BASE,
 				     flash_size)
diff --git a/board/Marvell/db64360/db64360.c b/board/Marvell/db64360/db64360.c
index 6cae686..38769e0 100644
--- a/board/Marvell/db64360/db64360.c
+++ b/board/Marvell/db64360/db64360.c
@@ -834,15 +834,11 @@ int mem_test_walk (void)
 /*********************************************************************/
 int testdram (void)
 {
-	char *s;
 	int rundata, runaddress, runwalk;
 
-	s = getenv ("testdramdata");
-	rundata = (s && (*s == 'y')) ? 1 : 0;
-	s = getenv ("testdramaddress");
-	runaddress = (s && (*s == 'y')) ? 1 : 0;
-	s = getenv ("testdramwalk");
-	runwalk = (s && (*s == 'y')) ? 1 : 0;
+	rundata = getenv_yesno("testdramdata") == 1;
+	runaddress = getenv_yesno("testdramaddress") == 1;
+	runwalk = getenv_yesno("testdramwalk") == 1;
 
 /*    rundata = 1; */
 /*    runaddress = 0; */
diff --git a/board/Marvell/db64460/db64460.c b/board/Marvell/db64460/db64460.c
index d4f58b3..ddb7ed5 100644
--- a/board/Marvell/db64460/db64460.c
+++ b/board/Marvell/db64460/db64460.c
@@ -834,15 +834,11 @@ int mem_test_walk (void)
 /*********************************************************************/
 int testdram (void)
 {
-	char *s;
 	int rundata, runaddress, runwalk;
 
-	s = getenv ("testdramdata");
-	rundata = (s && (*s == 'y')) ? 1 : 0;
-	s = getenv ("testdramaddress");
-	runaddress = (s && (*s == 'y')) ? 1 : 0;
-	s = getenv ("testdramwalk");
-	runwalk = (s && (*s == 'y')) ? 1 : 0;
+	rundata = getenv_yesno("testdramdata") == 1;
+	runaddress = getenv_yesno("testdramaddress") == 1;
+	runwalk = getenv_yesno("testdramwalk") == 1;
 
 /*    rundata = 1; */
 /*    runaddress = 0; */
diff --git a/board/esd/cpci750/cpci750.c b/board/esd/cpci750/cpci750.c
index 98051fb..d7deae4 100644
--- a/board/esd/cpci750/cpci750.c
+++ b/board/esd/cpci750/cpci750.c
@@ -953,22 +953,18 @@ int mem_test_walk (void)
 /*********************************************************************/
 int testdram (void)
 {
-	char *s;
 	int rundata    = 0;
 	int runaddress = 0;
 	int runwalk    = 0;
 
 #ifdef CONFIG_SYS_DRAM_TEST_DATA
-	s = getenv ("testdramdata");
-	rundata = (s && (*s == 'y')) ? 1 : 0;
+	rundata = getenv_yesno("testdramdata") == 1;
 #endif
 #ifdef CONFIG_SYS_DRAM_TEST_ADDRESS
-	s = getenv ("testdramaddress");
-	runaddress = (s && (*s == 'y')) ? 1 : 0;
+	runaddress = getenv_yesno("testdramaddress") == 1;
 #endif
 #ifdef CONFIG_SYS_DRAM_TEST_WALK
-	s = getenv ("testdramwalk");
-	runwalk = (s && (*s == 'y')) ? 1 : 0;
+	runwalk = getenv_yesno("testdramwalk") == 1;
 #endif
 
 	if ((rundata == 1) || (runaddress == 1) || (runwalk == 1)) {
diff --git a/board/gw8260/gw8260.c b/board/gw8260/gw8260.c
index 77a1e1d..64c54d5 100644
--- a/board/gw8260/gw8260.c
+++ b/board/gw8260/gw8260.c
@@ -544,15 +544,11 @@ int mem_test_walk (void)
 /*********************************************************************/
 int testdram (void)
 {
-	char *s;
 	int rundata, runaddress, runwalk;
 
-	s = getenv ("testdramdata");
-	rundata = (s && (*s == 'y')) ? 1 : 0;
-	s = getenv ("testdramaddress");
-	runaddress = (s && (*s == 'y')) ? 1 : 0;
-	s = getenv ("testdramwalk");
-	runwalk = (s && (*s == 'y')) ? 1 : 0;
+	rundata = getenv_yesno("testdramdata") == 1;
+	runaddress = getenv_yesno("testdramaddress") == 1;
+	runwalk = getenv_yesno("testdramwalk") == 1;
 
 	if ((rundata == 1) || (runaddress == 1) || (runwalk == 1)) {
 		printf ("Testing RAM ... ");
diff --git a/board/prodrive/p3mx/p3mx.c b/board/prodrive/p3mx/p3mx.c
index 389affc..c3fd191 100644
--- a/board/prodrive/p3mx/p3mx.c
+++ b/board/prodrive/p3mx/p3mx.c
@@ -768,22 +768,18 @@ int mem_test_walk (void)
 /*********************************************************************/
 int testdram (void)
 {
-	char *s;
 	int rundata    = 0;
 	int runaddress = 0;
 	int runwalk    = 0;
 
 #ifdef CONFIG_SYS_DRAM_TEST_DATA
-	s = getenv ("testdramdata");
-	rundata = (s && (*s == 'y')) ? 1 : 0;
+	rundata = getenv_yesno("testdramdata") == 1;
 #endif
 #ifdef CONFIG_SYS_DRAM_TEST_ADDRESS
-	s = getenv ("testdramaddress");
-	runaddress = (s && (*s == 'y')) ? 1 : 0;
+	runaddress = getenv_yesno("testdramaddress") == 1;
 #endif
 #ifdef CONFIG_SYS_DRAM_TEST_WALK
-	s = getenv ("testdramwalk");
-	runwalk = (s && (*s == 'y')) ? 1 : 0;
+	runwalk = getenv_yesno("testdramwalk") == 1;
 #endif
 
 	if ((rundata == 1) || (runaddress == 1) || (runwalk == 1))
diff --git a/common/env_common.c b/common/env_common.c
index a960aa8..067fe3f 100644
--- a/common/env_common.c
+++ b/common/env_common.c
@@ -81,6 +81,20 @@ const uchar *env_get_addr(int index)
 		return &default_environment[index];
 }
 
+/*
+ * Read an environment variable as a boolean
+ * Return -1 if variable does not exist (default to true)
+ */
+int getenv_yesno(const char *var)
+{
+	char *s = getenv(var);
+
+	if (s == NULL)
+		return -1;
+	return (*s == '1' || *s == 'y' || *s == 'Y' || *s == 't' || *s == 'T') ?
+		1 : 0;
+}
+
 void set_default_env(const char *s)
 {
 	int flags = 0;
diff --git a/common/image.c b/common/image.c
index e93b6e8..69e888c 100644
--- a/common/image.c
+++ b/common/image.c
@@ -416,12 +416,6 @@ static const image_header_t *image_get_ramdisk(ulong rd_addr, uint8_t arch,
 /* Shared dual-format routines */
 /*****************************************************************************/
 #ifndef USE_HOSTCC
-int getenv_yesno(char *var)
-{
-	char *s = getenv(var);
-	return (s && (*s == 'n')) ? 0 : 1;
-}
-
 ulong getenv_bootm_low(void)
 {
 	char *s = getenv("bootm_low");
diff --git a/include/common.h b/include/common.h
index 5e3c5ee..d0bf1e8 100644
--- a/include/common.h
+++ b/include/common.h
@@ -340,6 +340,11 @@ int	envmatch     (uchar *, int);
 char	*getenv	     (const char *);
 int	getenv_f     (const char *name, char *buf, unsigned len);
 ulong getenv_ulong(const char *name, int base, ulong default_val);
+/*
+ * Read an environment variable as a boolean
+ * Return -1 if variable does not exist (default to true)
+ */
+int getenv_yesno(const char *var);
 int	saveenv	     (void);
 int	setenv	     (const char *, const char *);
 int setenv_ulong(const char *varname, ulong value);
diff --git a/include/image.h b/include/image.h
index f54d983..b958b18 100644
--- a/include/image.h
+++ b/include/image.h
@@ -460,7 +460,6 @@ static inline void image_set_name(image_header_t *hdr, const char *name)
 int image_check_hcrc(const image_header_t *hdr);
 int image_check_dcrc(const image_header_t *hdr);
 #ifndef USE_HOSTCC
-int getenv_yesno(char *var);
 ulong getenv_bootm_low(void);
 phys_size_t getenv_bootm_size(void);
 phys_size_t getenv_bootm_mapsize(void);
diff --git a/net/net.c b/net/net.c
index 82c4cc9..da68a61 100644
--- a/net/net.c
+++ b/net/net.c
@@ -214,26 +214,24 @@ static int NetTryCount;
  */
 void net_auto_load(void)
 {
+#if defined(CONFIG_CMD_NFS)
 	const char *s = getenv("autoload");
 
-	if (s != NULL) {
-		if (*s == 'n') {
-			/*
-			 * Just use BOOTP/RARP to configure system;
-			 * Do not use TFTP to load the bootfile.
-			 */
-			net_set_state(NETLOOP_SUCCESS);
-			return;
-		}
-#if defined(CONFIG_CMD_NFS)
-		if (strcmp(s, "NFS") == 0) {
-			/*
-			 * Use NFS to load the bootfile.
-			 */
-			NfsStart();
-			return;
-		}
+	if (s != NULL && strcmp(s, "NFS") == 0) {
+		/*
+		 * Use NFS to load the bootfile.
+		 */
+		NfsStart();
+		return;
+	}
 #endif
+	if (getenv_yesno("autoload") == 0) {
+		/*
+		 * Just use BOOTP/RARP to configure system;
+		 * Do not use TFTP to load the bootfile.
+		 */
+		net_set_state(NETLOOP_SUCCESS);
+		return;
 	}
 	TftpStart(TFTPGET);
 }
-- 
1.7.11.5

^ permalink raw reply related	[flat|nested] 124+ messages in thread

* [U-Boot] [PATCH v5 06/20] env: Hide '.' variables in env print by default
  2012-12-12  4:16                                           ` [U-Boot] [PATCH v5 " Joe Hershberger
                                                               ` (4 preceding siblings ...)
  2012-12-12  4:16                                             ` [U-Boot] [PATCH v5 05/20] env: Use getenv_yesno() more generally Joe Hershberger
@ 2012-12-12  4:16                                             ` Joe Hershberger
  2012-12-12  4:16                                             ` [U-Boot] [PATCH v5 07/20] env: Add support for callbacks to environment vars Joe Hershberger
                                                               ` (14 subsequent siblings)
  20 siblings, 0 replies; 124+ messages in thread
From: Joe Hershberger @ 2012-12-12  4:16 UTC (permalink / raw)
  To: u-boot

When printing all variables with env print, don't print variables that
begin with '.'.  If env print is called with a '-a' switch, then
include variables that begin with '.' (just like the ls command).

Variables printed explicitly will be printed even without the -a.

Signed-off-by: Joe Hershberger <joe.hershberger@ni.com>
---
Changes in v5: None
Changes in v4:
- Fixed help text

Changes in v3: None
Changes in v2: None

 board/esd/pmc440/cmd_pmc440.c |  2 +-
 common/cmd_nvedit.c           | 26 +++++++++++++++++---------
 common/env_dataflash.c        |  2 +-
 common/env_eeprom.c           |  2 +-
 common/env_fat.c              |  2 +-
 common/env_flash.c            |  4 ++--
 common/env_mmc.c              |  2 +-
 common/env_nand.c             |  4 ++--
 common/env_nvram.c            |  2 +-
 common/env_onenand.c          |  2 +-
 common/env_sf.c               |  4 ++--
 include/search.h              |  5 +++--
 lib/hashtable.c               |  5 ++++-
 13 files changed, 37 insertions(+), 25 deletions(-)

diff --git a/board/esd/pmc440/cmd_pmc440.c b/board/esd/pmc440/cmd_pmc440.c
index f1ffb7b..e9a78a3 100644
--- a/board/esd/pmc440/cmd_pmc440.c
+++ b/board/esd/pmc440/cmd_pmc440.c
@@ -391,7 +391,7 @@ int do_painit(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
 	nextbase -= ((CONFIG_ENV_SIZE + 4096 - 1) & ~(4096 - 1));
 	envp = (env_t *)nextbase;
 	res = (char *)envp->data;
-	len = hexport_r(&env_htab, '\0', &res, ENV_SIZE, 0, NULL);
+	len = hexport_r(&env_htab, '\0', 0, &res, ENV_SIZE, 0, NULL);
 	if (len < 0) {
 		error("Cannot export environment: errno = %d\n", errno);
 		return 1;
diff --git a/common/cmd_nvedit.c b/common/cmd_nvedit.c
index da5689c..022ad39 100644
--- a/common/cmd_nvedit.c
+++ b/common/cmd_nvedit.c
@@ -106,7 +106,7 @@ int get_env_id(void)
  *
  * Returns 0 in case of error, or length of printed string
  */
-static int env_print(char *name)
+static int env_print(char *name, int flag)
 {
 	char *res = NULL;
 	size_t len;
@@ -116,7 +116,7 @@ static int env_print(char *name)
 
 		e.key = name;
 		e.data = NULL;
-		hsearch_r(e, FIND, &ep, &env_htab, 0);
+		hsearch_r(e, FIND, &ep, &env_htab, flag);
 		if (ep == NULL)
 			return 0;
 		len = printf("%s=%s\n", ep->key, ep->data);
@@ -124,7 +124,7 @@ static int env_print(char *name)
 	}
 
 	/* print whole list */
-	len = hexport_r(&env_htab, '\n', &res, 0, 0, NULL);
+	len = hexport_r(&env_htab, '\n', flag, &res, 0, 0, NULL);
 
 	if (len > 0) {
 		puts(res);
@@ -141,10 +141,17 @@ static int do_env_print(cmd_tbl_t *cmdtp, int flag, int argc,
 {
 	int i;
 	int rcode = 0;
+	int env_flag = H_HIDE_DOT;
+
+	if (argc > 1 && argv[1][0] == '-' && argv[1][1] == 'a') {
+		argc--;
+		argv++;
+		env_flag &= ~H_HIDE_DOT;
+	}
 
 	if (argc == 1) {
 		/* print all env vars */
-		rcode = env_print(NULL);
+		rcode = env_print(NULL, env_flag);
 		if (!rcode)
 			return 1;
 		printf("\nEnvironment size: %d/%ld bytes\n",
@@ -153,8 +160,9 @@ static int do_env_print(cmd_tbl_t *cmdtp, int flag, int argc,
 	}
 
 	/* print selected env vars */
+	env_flag &= ~H_HIDE_DOT;
 	for (i = 1; i < argc; ++i) {
-		int rc = env_print(argv[i]);
+		int rc = env_print(argv[i], env_flag);
 		if (!rc) {
 			printf("## Error: \"%s\" not defined\n", argv[i]);
 			++rcode;
@@ -807,7 +815,7 @@ NXTARG:		;
 	argv++;
 
 	if (sep) {		/* export as text file */
-		len = hexport_r(&env_htab, sep, &addr, size, argc, argv);
+		len = hexport_r(&env_htab, sep, 0, &addr, size, argc, argv);
 		if (len < 0) {
 			error("Cannot export environment: errno = %d\n", errno);
 			return 1;
@@ -825,7 +833,7 @@ NXTARG:		;
 	else			/* export as raw binary data */
 		res = addr;
 
-	len = hexport_r(&env_htab, '\0', &res, ENV_SIZE, argc, argv);
+	len = hexport_r(&env_htab, '\0', 0, &res, ENV_SIZE, argc, argv);
 	if (len < 0) {
 		error("Cannot export environment: errno = %d\n", errno);
 		return 1;
@@ -1037,7 +1045,7 @@ static char env_help_text[] =
 #if defined(CONFIG_CMD_IMPORTENV)
 	"env import [-d] [-t | -b | -c] addr [size] - import environment\n"
 #endif
-	"env print [name ...] - print environment\n"
+	"env print [-a | name ...] - print environment\n"
 #if defined(CONFIG_CMD_RUN)
 	"env run var [...] - run commands in an environment variable\n"
 #endif
@@ -1069,7 +1077,7 @@ U_BOOT_CMD_COMPLETE(
 U_BOOT_CMD_COMPLETE(
 	printenv, CONFIG_SYS_MAXARGS, 1,	do_env_print,
 	"print environment variables",
-	"\n    - print values of all environment variables\n"
+	"[-a]\n    - print [all] values of all environment variables\n"
 	"printenv name ...\n"
 	"    - print value of environment variable 'name'",
 	var_complete
diff --git a/common/env_dataflash.c b/common/env_dataflash.c
index 3c5af37..38c9615 100644
--- a/common/env_dataflash.c
+++ b/common/env_dataflash.c
@@ -60,7 +60,7 @@ int saveenv(void)
 	char	*res;
 
 	res = (char *)&env_new.data;
-	len = hexport_r(&env_htab, '\0', &res, ENV_SIZE, 0, NULL);
+	len = hexport_r(&env_htab, '\0', 0, &res, ENV_SIZE, 0, NULL);
 	if (len < 0) {
 		error("Cannot export environment: errno = %d\n", errno);
 		return 1;
diff --git a/common/env_eeprom.c b/common/env_eeprom.c
index b66bba2..45c935b 100644
--- a/common/env_eeprom.c
+++ b/common/env_eeprom.c
@@ -139,7 +139,7 @@ int saveenv(void)
 	BUG_ON(env_ptr != NULL);
 
 	res = (char *)&env_new.data;
-	len = hexport_r(&env_htab, '\0', &res, ENV_SIZE, 0, NULL);
+	len = hexport_r(&env_htab, '\0', 0, &res, ENV_SIZE, 0, NULL);
 	if (len < 0) {
 		error("Cannot export environment: errno = %d\n", errno);
 		return 1;
diff --git a/common/env_fat.c b/common/env_fat.c
index 6ef5318..c0f18ab 100644
--- a/common/env_fat.c
+++ b/common/env_fat.c
@@ -61,7 +61,7 @@ int saveenv(void)
 	int err;
 
 	res = (char *)&env_new.data;
-	len = hexport_r(&env_htab, '\0', &res, ENV_SIZE, 0, NULL);
+	len = hexport_r(&env_htab, '\0', 0, &res, ENV_SIZE, 0, NULL);
 	if (len < 0) {
 		error("Cannot export environment: errno = %d\n", errno);
 		return 1;
diff --git a/common/env_flash.c b/common/env_flash.c
index aa970d4..e07d336 100644
--- a/common/env_flash.c
+++ b/common/env_flash.c
@@ -142,7 +142,7 @@ int saveenv(void)
 		goto done;
 
 	res = (char *)&env_new.data;
-	len = hexport_r(&env_htab, '\0', &res, ENV_SIZE, 0, NULL);
+	len = hexport_r(&env_htab, '\0', 0, &res, ENV_SIZE, 0, NULL);
 	if (len < 0) {
 		error("Cannot export environment: errno = %d\n", errno);
 		goto done;
@@ -275,7 +275,7 @@ int saveenv(void)
 		goto done;
 
 	res = (char *)&env_new.data;
-	len = hexport_r(&env_htab, '\0', &res, ENV_SIZE, 0, NULL);
+	len = hexport_r(&env_htab, '\0', 0, &res, ENV_SIZE, 0, NULL);
 	if (len < 0) {
 		error("Cannot export environment: errno = %d\n", errno);
 		goto done;
diff --git a/common/env_mmc.c b/common/env_mmc.c
index a2ff90b..ce21671 100644
--- a/common/env_mmc.c
+++ b/common/env_mmc.c
@@ -130,7 +130,7 @@ int saveenv(void)
 	}
 
 	res = (char *)&env_new->data;
-	len = hexport_r(&env_htab, '\0', &res, ENV_SIZE, 0, NULL);
+	len = hexport_r(&env_htab, '\0', 0, &res, ENV_SIZE, 0, NULL);
 	if (len < 0) {
 		error("Cannot export environment: errno = %d\n", errno);
 		ret = 1;
diff --git a/common/env_nand.c b/common/env_nand.c
index 79e8033..22e72a2 100644
--- a/common/env_nand.c
+++ b/common/env_nand.c
@@ -186,7 +186,7 @@ int saveenv(void)
 		return 1;
 
 	res = (char *)&env_new.data;
-	len = hexport_r(&env_htab, '\0', &res, ENV_SIZE, 0, NULL);
+	len = hexport_r(&env_htab, '\0', 0, &res, ENV_SIZE, 0, NULL);
 	if (len < 0) {
 		error("Cannot export environment: errno = %d\n", errno);
 		return 1;
@@ -239,7 +239,7 @@ int saveenv(void)
 		return 1;
 
 	res = (char *)&env_new->data;
-	len = hexport_r(&env_htab, '\0', &res, ENV_SIZE, 0, NULL);
+	len = hexport_r(&env_htab, '\0', 0, &res, ENV_SIZE, 0, NULL);
 	if (len < 0) {
 		error("Cannot export environment: errno = %d\n", errno);
 		return 1;
diff --git a/common/env_nvram.c b/common/env_nvram.c
index 6483db3..eab0e7b 100644
--- a/common/env_nvram.c
+++ b/common/env_nvram.c
@@ -90,7 +90,7 @@ int saveenv(void)
 	int	rcode = 0;
 
 	res = (char *)&env_new.data;
-	len = hexport_r(&env_htab, '\0', &res, ENV_SIZE, 0, NULL);
+	len = hexport_r(&env_htab, '\0', 0, &res, ENV_SIZE, 0, NULL);
 	if (len < 0) {
 		error("Cannot export environment: errno = %d\n", errno);
 		return 1;
diff --git a/common/env_onenand.c b/common/env_onenand.c
index da35071..faa903d 100644
--- a/common/env_onenand.c
+++ b/common/env_onenand.c
@@ -95,7 +95,7 @@ int saveenv(void)
 	};
 
 	res = (char *)&env_new.data;
-	len = hexport_r(&env_htab, '\0', &res, ENV_SIZE, 0, NULL);
+	len = hexport_r(&env_htab, '\0', 0, &res, ENV_SIZE, 0, NULL);
 	if (len < 0) {
 		error("Cannot export environment: errno = %d\n", errno);
 		return 1;
diff --git a/common/env_sf.c b/common/env_sf.c
index bbd472f..d9e9085 100644
--- a/common/env_sf.c
+++ b/common/env_sf.c
@@ -79,7 +79,7 @@ int saveenv(void)
 	}
 
 	res = (char *)&env_new.data;
-	len = hexport_r(&env_htab, '\0', &res, ENV_SIZE, 0, NULL);
+	len = hexport_r(&env_htab, '\0', 0, &res, ENV_SIZE, 0, NULL);
 	if (len < 0) {
 		error("Cannot export environment: errno = %d\n", errno);
 		return 1;
@@ -277,7 +277,7 @@ int saveenv(void)
 	}
 
 	res = (char *)&env_new.data;
-	len = hexport_r(&env_htab, '\0', &res, ENV_SIZE, 0, NULL);
+	len = hexport_r(&env_htab, '\0', 0, &res, ENV_SIZE, 0, NULL);
 	if (len < 0) {
 		error("Cannot export environment: errno = %d\n", errno);
 		goto done;
diff --git a/include/search.h b/include/search.h
index fa00ea1..1e48deb 100644
--- a/include/search.h
+++ b/include/search.h
@@ -107,7 +107,7 @@ extern int hdelete_r(const char *__key, struct hsearch_data *__htab,
 		     int __flag);
 
 extern ssize_t hexport_r(struct hsearch_data *__htab,
-		     const char __sep, char **__resp, size_t __size,
+		     const char __sep, int __flag, char **__resp, size_t __size,
 		     int argc, char * const argv[]);
 
 /*
@@ -120,9 +120,10 @@ extern int himport_r(struct hsearch_data *__htab,
 		     const char *__env, size_t __size, const char __sep,
 		     int __flag, int nvars, char * const vars[]);
 
-/* Flags for himport_r(), hdelete_r(), and hsearch_r() */
+/* Flags for himport_r(), hexport_r(), hdelete_r(), and hsearch_r() */
 #define H_NOCLEAR	(1 << 0) /* do not clear hash table before importing */
 #define H_FORCE		(1 << 1) /* overwrite read-only/write-once variables */
 #define H_INTERACTIVE	(1 << 2) /* indicate that an import is user directed */
+#define H_HIDE_DOT	(1 << 3) /* don't print env vars that begin with '.' */
 
 #endif /* search.h */
diff --git a/lib/hashtable.c b/lib/hashtable.c
index 6861a42..7c6b96c 100644
--- a/lib/hashtable.c
+++ b/lib/hashtable.c
@@ -522,7 +522,7 @@ static int cmpkey(const void *p1, const void *p2)
 	return (strcmp(e1->key, e2->key));
 }
 
-ssize_t hexport_r(struct hsearch_data *htab, const char sep,
+ssize_t hexport_r(struct hsearch_data *htab, const char sep, int flag,
 		 char **resp, size_t size,
 		 int argc, char * const argv[])
 {
@@ -559,6 +559,9 @@ ssize_t hexport_r(struct hsearch_data *htab, const char sep,
 			if ((argc > 0) && (found == 0))
 				continue;
 
+			if ((flag & H_HIDE_DOT) && ep->key[0] == '.')
+				continue;
+
 			list[n++] = ep;
 
 			totlen += strlen(ep->key) + 2;
-- 
1.7.11.5

^ permalink raw reply related	[flat|nested] 124+ messages in thread

* [U-Boot] [PATCH v5 07/20] env: Add support for callbacks to environment vars
  2012-12-12  4:16                                           ` [U-Boot] [PATCH v5 " Joe Hershberger
                                                               ` (5 preceding siblings ...)
  2012-12-12  4:16                                             ` [U-Boot] [PATCH v5 06/20] env: Hide '.' variables in env print by default Joe Hershberger
@ 2012-12-12  4:16                                             ` Joe Hershberger
  2013-01-11  8:06                                               ` Stefan Roese
  2012-12-12  4:16                                             ` [U-Boot] [PATCH v5 08/20] env: Add a command to view callbacks Joe Hershberger
                                                               ` (13 subsequent siblings)
  20 siblings, 1 reply; 124+ messages in thread
From: Joe Hershberger @ 2012-12-12  4:16 UTC (permalink / raw)
  To: u-boot

Add support for per-variable callbacks to the "hashtable" functions.

Signed-off-by: Joe Hershberger <joe.hershberger@ni.com>

!!!fix comment in callback
---
Changes in v5:
- Add support for CONFIG_NEEDS_MANUAL_RELOC boards
- Fixed comment typo

Changes in v4: None
Changes in v3:
- Use Marek's linker lists instead of implementing it directly
- Rebase onto latest master
- Add flags parameter to callbacks
- Implement reverse search in env_attr_lookup()
- Fix space skipping in env_attr_lookup()
- All errors coming back from hsearch_r() are no longer fatal.  Don't
abort import on failed ENTER action.
- Removed checkpatch.pl warning

Changes in v2:
- Added much-needed documentation
- Factored out prevch and nextch in env_attr_lookup()

 README                 |  30 +++++++
 common/Makefile        |   4 +
 common/env_attr.c      | 222 +++++++++++++++++++++++++++++++++++++++++++++++++
 common/env_callback.c  | 144 ++++++++++++++++++++++++++++++++
 include/env_attr.h     |  55 ++++++++++++
 include/env_callback.h |  62 ++++++++++++++
 include/env_default.h  |   5 ++
 include/environment.h  |   2 +
 include/search.h       |   5 ++
 lib/hashtable.c        |  67 ++++++++++++++-
 10 files changed, 592 insertions(+), 4 deletions(-)
 create mode 100644 common/env_attr.c
 create mode 100644 common/env_callback.c
 create mode 100644 include/env_attr.h
 create mode 100644 include/env_callback.h

diff --git a/README b/README
index ed7d270..6b1698c 100644
--- a/README
+++ b/README
@@ -4168,6 +4168,36 @@ Please note that changes to some configuration parameters may take
 only effect after the next boot (yes, that's just like Windoze :-).
 
 
+Callback functions for environment variables:
+---------------------------------------------
+
+For some environment variables, the behavior of u-boot needs to change
+when their values are changed.  This functionailty allows functions to
+be associated with arbitrary variables.  On creation, overwrite, or
+deletion, the callback will provide the opportunity for some side
+effect to happen or for the change to be rejected.
+
+The callbacks are named and associated with a function using the
+U_BOOT_ENV_CALLBACK macro in your board or driver code.
+
+These callbacks are associated with variables in one of two ways.  The
+static list can be added to by defining CONFIG_ENV_CALLBACK_LIST_STATIC
+in the board configuration to a string that defines a list of
+associations.  The list must be in the following format:
+
+	entry = variable_name[:callback_name]
+	list = entry[,list]
+
+If the callback name is not specified, then the callback is deleted.
+Spaces are also allowed anywhere in the list.
+
+Callbacks can also be associated by defining the ".callbacks" variable
+with the same list format above.  Any association in ".callbacks" will
+override any association in the static list. You can define
+CONFIG_ENV_CALLBACK_LIST_DEFAULT to a list (string) to define the
+".callbacks" envirnoment variable in the default or embedded environment.
+
+
 Command Line Parsing:
 =====================
 
diff --git a/common/Makefile b/common/Makefile
index 9e43322..af6e8f9 100644
--- a/common/Makefile
+++ b/common/Makefile
@@ -43,6 +43,8 @@ COBJS-y += cmd_nvedit.o
 COBJS-y += cmd_version.o
 
 # environment
+COBJS-y += env_attr.o
+COBJS-y += env_callback.o
 COBJS-y += env_common.o
 COBJS-$(CONFIG_ENV_IS_IN_DATAFLASH) += env_dataflash.o
 COBJS-$(CONFIG_ENV_IS_IN_EEPROM) += env_eeprom.o
@@ -197,6 +199,8 @@ endif
 ifdef CONFIG_SPL_BUILD
 COBJS-$(CONFIG_SPL_YMODEM_SUPPORT) += xyzModem.o
 COBJS-$(CONFIG_SPL_NET_SUPPORT) += cmd_nvedit.o
+COBJS-$(CONFIG_SPL_NET_SUPPORT) += env_attr.o
+COBJS-$(CONFIG_SPL_NET_SUPPORT) += env_callback.o
 COBJS-$(CONFIG_SPL_NET_SUPPORT) += env_common.o
 COBJS-$(CONFIG_SPL_NET_SUPPORT) += env_nowhere.o
 COBJS-$(CONFIG_SPL_NET_SUPPORT) += miiphyutil.o
diff --git a/common/env_attr.c b/common/env_attr.c
new file mode 100644
index 0000000..7d330a5
--- /dev/null
+++ b/common/env_attr.c
@@ -0,0 +1,222 @@
+/*
+ * (C) Copyright 2012
+ * Joe Hershberger, National Instruments, joe.hershberger at 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
+ */
+
+#include <common.h>
+#include <env_attr.h>
+#include <errno.h>
+#include <linux/string.h>
+#include <malloc.h>
+
+/*
+ * Iterate through the whole list calling the callback for each found element.
+ * "attr_list" takes the form:
+ *	attributes = [^,:\s]*
+ *	entry = name[:attributes]
+ *	list = entry[,list]
+ */
+int env_attr_walk(const char *attr_list,
+	int (*callback)(const char *name, const char *attributes))
+{
+	const char *entry, *entry_end;
+	char *name, *attributes;
+
+	if (!attr_list)
+		/* list not found */
+		return 1;
+
+	entry = attr_list;
+	do {
+		char *entry_cpy = NULL;
+
+		entry_end = strchr(entry, ENV_ATTR_LIST_DELIM);
+		/* check if this is the last entry in the list */
+		if (entry_end == NULL) {
+			int entry_len = strlen(entry);
+
+			if (entry_len) {
+				/*
+				 * allocate memory to copy the entry into since
+				 * we will need to inject '\0' chars and squash
+				 * white-space before calling the callback
+				 */
+				entry_cpy = malloc(entry_len + 1);
+				if (entry_cpy)
+					/* copy the rest of the list */
+					strcpy(entry_cpy, entry);
+				else
+					return -ENOMEM;
+			}
+		} else {
+			int entry_len = entry_end - entry;
+
+			if (entry_len) {
+				/*
+				 * allocate memory to copy the entry into since
+				 * we will need to inject '\0' chars and squash
+				 * white-space before calling the callback
+				 */
+				entry_cpy = malloc(entry_len + 1);
+				if (entry_cpy) {
+					/* copy just this entry and null term */
+					strncpy(entry_cpy, entry, entry_len);
+					entry_cpy[entry_len] = '\0';
+				} else
+					return -ENOMEM;
+			}
+		}
+
+		/* check if there is anything to process (e.g. not ",,,") */
+		if (entry_cpy != NULL) {
+			attributes = strchr(entry_cpy, ENV_ATTR_SEP);
+			/* check if there is a ':' */
+			if (attributes != NULL) {
+				/* replace the ':' with '\0' to term name */
+				*attributes++ = '\0';
+				/* remove white-space from attributes */
+				attributes = strim(attributes);
+			}
+			/* remove white-space from name */
+			name = strim(entry_cpy);
+
+			/* only call the callback if there is a name */
+			if (strlen(name) != 0) {
+				int retval = 0;
+
+				retval = callback(name, attributes);
+				if (retval) {
+					free(entry_cpy);
+					return retval;
+				}
+			}
+		}
+
+		free(entry_cpy);
+		entry = entry_end + 1;
+	} while (entry_end != NULL);
+
+	return 0;
+}
+
+/*
+ * Search for the last matching string in another string with the option to
+ * start looking at a certain point (i.e. ignore anything beyond that point).
+ */
+static char *reverse_strstr(const char *searched, const char *search_for,
+	const char *searched_start)
+{
+	char *result = NULL;
+
+	if (*search_for == '\0')
+		return (char *)searched;
+
+	for (;;) {
+		char *match = strstr(searched, search_for);
+
+		/*
+		 * Stop looking if no new match is found or looking past the
+		 * searched_start pointer
+		 */
+		if (match == NULL || (searched_start != NULL &&
+		    match + strlen(search_for) > searched_start))
+			break;
+
+		result = match;
+		searched = match + 1;
+	}
+
+	return result;
+}
+
+/*
+ * Retrieve the attributes string associated with a single name in the list
+ * There is no protection on attributes being too small for the value
+ */
+int env_attr_lookup(const char *attr_list, const char *name, char *attributes)
+{
+	const char *entry = NULL;
+
+	if (!attributes)
+		/* bad parameter */
+		return -1;
+	if (!attr_list)
+		/* list not found */
+		return 1;
+
+	entry = reverse_strstr(attr_list, name, NULL);
+	while (entry != NULL) {
+		const char *prevch = entry - 1;
+		const char *nextch = entry + strlen(name);
+
+		/* Skip spaces */
+		while (*prevch == ' ')
+			prevch--;
+		while (*nextch == ' ')
+			nextch++;
+
+		/* check for an exact match */
+		if ((entry == attr_list ||
+		     *prevch == ENV_ATTR_LIST_DELIM) &&
+		    (*nextch == ENV_ATTR_SEP ||
+		     *nextch == ENV_ATTR_LIST_DELIM ||
+		     *nextch == '\0'))
+			break;
+
+		entry = reverse_strstr(attr_list, name, entry);
+	}
+	if (entry != NULL) {
+		int len;
+
+		/* skip the name */
+		entry += strlen(name);
+		/* skip spaces */
+		while (*entry == ' ')
+			entry++;
+		if (*entry != ENV_ATTR_SEP)
+			len = 0;
+		else {
+			const char *delim;
+			static const char delims[] = {
+				ENV_ATTR_LIST_DELIM, ' ', '\0'};
+
+			/* skip the attr sep */
+			entry += 1;
+			/* skip spaces */
+			while (*entry == ' ')
+				entry++;
+
+			delim = strpbrk(entry, delims);
+			if (delim == NULL)
+				len = strlen(entry);
+			else
+				len = delim - entry;
+			memcpy(attributes, entry, len);
+		}
+		attributes[len] = '\0';
+
+		/* success */
+		return 0;
+	}
+
+	/* not found in list */
+	return 2;
+}
diff --git a/common/env_callback.c b/common/env_callback.c
new file mode 100644
index 0000000..78ca367
--- /dev/null
+++ b/common/env_callback.c
@@ -0,0 +1,144 @@
+/*
+ * (C) Copyright 2012
+ * Joe Hershberger, National Instruments, joe.hershberger at 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
+ */
+
+#include <common.h>
+#include <environment.h>
+
+#if defined(CONFIG_NEEDS_MANUAL_RELOC)
+DECLARE_GLOBAL_DATA_PTR;
+#endif
+
+/*
+ * Look up a callback function pointer by name
+ */
+struct env_clbk_tbl *find_env_callback(const char *name)
+{
+	struct env_clbk_tbl *clbkp;
+	int i;
+	int num_callbacks = ll_entry_count(struct env_clbk_tbl, env_clbk);
+
+	if (name == NULL)
+		return NULL;
+
+	/* look up the callback in the linker-list */
+	for (i = 0, clbkp = ll_entry_start(struct env_clbk_tbl, env_clbk);
+	     i < num_callbacks;
+	     i++, clbkp++) {
+		if (strcmp(name, clbkp->name) == 0)
+			return clbkp;
+	}
+
+	return NULL;
+}
+
+/*
+ * Look for a possible callback for a newly added variable
+ * This is called specifically when the variable did not exist in the hash
+ * previously, so the blanket update did not find this variable.
+ */
+void env_callback_init(ENTRY *var_entry)
+{
+	const char *var_name = var_entry->key;
+	const char *callback_list = getenv(ENV_CALLBACK_VAR);
+	char callback_name[256] = "";
+	struct env_clbk_tbl *clbkp;
+	int ret = 1;
+
+	/* look in the ".callbacks" var for a reference to this variable */
+	if (callback_list != NULL)
+		ret = env_attr_lookup(callback_list, var_name, callback_name);
+
+	/* only if not found there, look in the static list */
+	if (ret)
+		ret = env_attr_lookup(ENV_CALLBACK_LIST_STATIC, var_name,
+			callback_name);
+
+	/* if an association was found, set the callback pointer */
+	if (!ret && strlen(callback_name)) {
+		clbkp = find_env_callback(callback_name);
+		if (clbkp != NULL)
+#if defined(CONFIG_NEEDS_MANUAL_RELOC)
+			var_entry->callback = clbkp->callback + gd->reloc_off;
+#else
+			var_entry->callback = clbkp->callback;
+#endif
+	}
+}
+
+/*
+ * Called on each existing env var prior to the blanket update since removing
+ * a callback association should remove its callback.
+ */
+static int clear_callback(ENTRY *entry)
+{
+	entry->callback = NULL;
+
+	return 0;
+}
+
+/*
+ * Call for each element in the list that associates variables to callbacks
+ */
+static int set_callback(const char *name, const char *value)
+{
+	ENTRY e, *ep;
+	struct env_clbk_tbl *clbkp;
+
+	e.key	= name;
+	e.data	= NULL;
+	hsearch_r(e, FIND, &ep, &env_htab, 0);
+
+	/* does the env variable actually exist? */
+	if (ep != NULL) {
+		/* the assocaition delares no callback, so remove the pointer */
+		if (value == NULL || strlen(value) == 0)
+			ep->callback = NULL;
+		else {
+			/* assign the requested callback */
+			clbkp = find_env_callback(value);
+			if (clbkp != NULL)
+#if defined(CONFIG_NEEDS_MANUAL_RELOC)
+				ep->callback = clbkp->callback + gd->reloc_off;
+#else
+				ep->callback = clbkp->callback;
+#endif
+		}
+	}
+
+	return 0;
+}
+
+static int on_callbacks(const char *name, const char *value, enum env_op op,
+	int flags)
+{
+	/* remove all callbacks */
+	hwalk_r(&env_htab, clear_callback);
+
+	/* configure any static callback bindings */
+	env_attr_walk(ENV_CALLBACK_LIST_STATIC, set_callback);
+	/* configure any dynamic callback bindings */
+	env_attr_walk(value, set_callback);
+
+	return 0;
+}
+U_BOOT_ENV_CALLBACK(callbacks, on_callbacks);
diff --git a/include/env_attr.h b/include/env_attr.h
new file mode 100644
index 0000000..6ef114f
--- /dev/null
+++ b/include/env_attr.h
@@ -0,0 +1,55 @@
+/*
+ * (C) Copyright 2012
+ * Joe Hershberger, National Instruments, joe.hershberger at 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
+ */
+
+#ifndef __ENV_ATTR_H__
+#define __ENV_ATTR_H__
+
+#define ENV_ATTR_LIST_DELIM	','
+#define ENV_ATTR_SEP		':'
+
+/*
+ * env_attr_walk takes as input an "attr_list" that takes the form:
+ *	attributes = [^,:\s]*
+ *	entry = name[:attributes]
+ *	list = entry[,list]
+ * It will call the "callback" function with the "name" and attribute as "value"
+ * The callback may return a non-0 to abort the list walk.
+ * This return value will be passed through to the caller.
+ * 0 is returned on success.
+ */
+extern int env_attr_walk(const char *attr_list,
+	int (*callback)(const char *name, const char *value));
+
+/*
+ * env_attr_lookup takes as input an "attr_list" with the same form as above.
+ * It also takes as input a "name" to look for.
+ * If the name is found in the list, it's value is copied into "attributes".
+ * There is no protection on attributes being too small for the value.
+ * It returns -1 if attributes is NULL, 1 if "name" is not found, 2 if
+ * "attr_list" is NULL.
+ * Returns 0 on success.
+ */
+extern int env_attr_lookup(const char *attr_list, const char *name,
+	char *attributes);
+
+#endif /* __ENV_ATTR_H__ */
diff --git a/include/env_callback.h b/include/env_callback.h
new file mode 100644
index 0000000..5a460f3
--- /dev/null
+++ b/include/env_callback.h
@@ -0,0 +1,62 @@
+/*
+ * (C) Copyright 2012
+ * Joe Hershberger, National Instruments, joe.hershberger at 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
+ */
+
+#ifndef __ENV_CALLBACK_H__
+#define __ENV_CALLBACK_H__
+
+#include <linker_lists.h>
+#include <search.h>
+
+#define ENV_CALLBACK_VAR ".callbacks"
+
+/* Board configs can define additional static callback bindings */
+#ifndef CONFIG_ENV_CALLBACK_LIST_STATIC
+#define CONFIG_ENV_CALLBACK_LIST_STATIC
+#endif
+
+/*
+ * This list of callback bindings is static, but may be overridden by defining
+ * a new association in the ".callbacks" environment variable.
+ */
+#define ENV_CALLBACK_LIST_STATIC ENV_CALLBACK_VAR ":callbacks," \
+	CONFIG_ENV_CALLBACK_LIST_STATIC
+
+struct env_clbk_tbl {
+	const char *name;		/* Callback name */
+	int (*callback)(const char *name, const char *value, enum env_op op,
+		int flags);
+};
+
+struct env_clbk_tbl *find_env_callback(const char *);
+void env_callback_init(ENTRY *var_entry);
+
+/*
+ * Define a callback that can be associated with variables.
+ * when associated through the ".callbacks" environment variable, the callback
+ * will be executed any time the variable is inserted, overwritten, or deleted.
+ */
+#define U_BOOT_ENV_CALLBACK(name, callback) \
+	ll_entry_declare(struct env_clbk_tbl, name, env_clbk, env_clbk) = \
+	{#name, callback}
+
+#endif /* __ENV_CALLBACK_H__ */
diff --git a/include/env_default.h b/include/env_default.h
index a1db73a..d05eba1 100644
--- a/include/env_default.h
+++ b/include/env_default.h
@@ -24,6 +24,8 @@
  * MA 02111-1307 USA
  */
 
+#include <env_callback.h>
+
 #ifdef DEFAULT_ENV_INSTANCE_EMBEDDED
 env_t environment __PPCENV__ = {
 	ENV_CRC,	/* CRC Sum */
@@ -36,6 +38,9 @@ static char default_environment[] = {
 #else
 const uchar default_environment[] = {
 #endif
+#ifdef	CONFIG_ENV_CALLBACK_LIST_DEFAULT
+	ENV_CALLBACK_VAR "=" CONFIG_ENV_CALLBACK_LIST_DEFAULT "\0"
+#endif
 #ifdef	CONFIG_BOOTARGS
 	"bootargs="	CONFIG_BOOTARGS			"\0"
 #endif
diff --git a/include/environment.h b/include/environment.h
index 4b19f32..6c30215 100644
--- a/include/environment.h
+++ b/include/environment.h
@@ -164,6 +164,8 @@ extern void env_reloc(void);
 
 #ifndef DO_DEPS_ONLY
 
+#include <env_attr.h>
+#include <env_callback.h>
 #include <search.h>
 
 extern struct hsearch_data env_htab;
diff --git a/include/search.h b/include/search.h
index 1e48deb..d68e24a 100644
--- a/include/search.h
+++ b/include/search.h
@@ -47,6 +47,8 @@ typedef enum {
 typedef struct entry {
 	const char *key;
 	char *data;
+	int (*callback)(const char *name, const char *value, enum env_op op,
+		int flags);
 } ENTRY;
 
 /* Opaque type for internal use.  */
@@ -120,6 +122,9 @@ extern int himport_r(struct hsearch_data *__htab,
 		     const char *__env, size_t __size, const char __sep,
 		     int __flag, int nvars, char * const vars[]);
 
+/* Walk the whole table calling the callback on each element */
+extern int hwalk_r(struct hsearch_data *__htab, int (*callback)(ENTRY *));
+
 /* Flags for himport_r(), hexport_r(), hdelete_r(), and hsearch_r() */
 #define H_NOCLEAR	(1 << 0) /* do not clear hash table before importing */
 #define H_FORCE		(1 << 1) /* overwrite read-only/write-once variables */
diff --git a/lib/hashtable.c b/lib/hashtable.c
index 7c6b96c..e922666 100644
--- a/lib/hashtable.c
+++ b/lib/hashtable.c
@@ -54,7 +54,8 @@
 #define	CONFIG_ENV_MAX_ENTRIES 512
 #endif
 
-#include "search.h"
+#include <env_callback.h>
+#include <search.h>
 
 /*
  * [Aho,Sethi,Ullman] Compilers: Principles, Techniques and Tools, 1986
@@ -274,6 +275,17 @@ static inline int _compare_and_overwrite_entry(ENTRY item, ACTION action,
 				return 0;
 			}
 
+			/* If there is a callback, call it */
+			if (htab->table[idx].entry.callback &&
+			    htab->table[idx].entry.callback(item.key,
+			    item.data, env_op_overwrite, flag)) {
+				debug("callback() rejected setting variable "
+					"%s, skipping it!\n", item.key);
+				__set_errno(EINVAL);
+				*retval = NULL;
+				return 0;
+			}
+
 			free(htab->table[idx].entry.data);
 			htab->table[idx].entry.data = strdup(item.data);
 			if (!htab->table[idx].entry.data) {
@@ -398,6 +410,9 @@ int hsearch_r(ENTRY item, ACTION action, ENTRY ** retval,
 
 		++htab->filled;
 
+		/* This is a new entry, so look up a possible callback */
+		env_callback_init(&htab->table[idx].entry);
+
 		/* check for permission */
 		if (htab->change_ok != NULL && htab->change_ok(
 		    &htab->table[idx].entry, item.data, env_op_create, flag)) {
@@ -409,6 +424,18 @@ int hsearch_r(ENTRY item, ACTION action, ENTRY ** retval,
 			return 0;
 		}
 
+		/* If there is a callback, call it */
+		if (htab->table[idx].entry.callback &&
+		    htab->table[idx].entry.callback(item.key, item.data,
+		    env_op_create, flag)) {
+			debug("callback() rejected setting variable "
+				"%s, skipping it!\n", item.key);
+			_hdelete(item.key, htab, &htab->table[idx].entry, idx);
+			__set_errno(EINVAL);
+			*retval = NULL;
+			return 0;
+		}
+
 		/* return new entry */
 		*retval = &htab->table[idx].entry;
 		return 1;
@@ -437,6 +464,7 @@ static void _hdelete(const char *key, struct hsearch_data *htab, ENTRY *ep,
 	debug("hdelete: DELETING key \"%s\"\n", key);
 	free((void *)ep->key);
 	free(ep->data);
+	ep->callback = NULL;
 	htab->table[idx].used = -1;
 
 	--htab->filled;
@@ -466,6 +494,15 @@ int hdelete_r(const char *key, struct hsearch_data *htab, int flag)
 		return 0;
 	}
 
+	/* If there is a callback, call it */
+	if (htab->table[idx].entry.callback &&
+	    htab->table[idx].entry.callback(key, NULL, env_op_delete, flag)) {
+		debug("callback() rejected deleting variable "
+			"%s, skipping it!\n", key);
+		__set_errno(EINVAL);
+		return 0;
+	}
+
 	_hdelete(key, htab, ep, idx);
 
 	return 1;
@@ -838,11 +875,9 @@ int himport_r(struct hsearch_data *htab,
 		e.data = value;
 
 		hsearch_r(e, ENTER, &rv, htab, flag);
-		if (rv == NULL) {
+		if (rv == NULL)
 			printf("himport_r: can't insert \"%s=%s\" into hash table\n",
 				name, value);
-			return 0;
-		}
 
 		debug("INSERT: table %p, filled %d/%d rv %p ==> name=\"%s\" value=\"%s\"\n",
 			htab, htab->filled, htab->size,
@@ -873,3 +908,27 @@ int himport_r(struct hsearch_data *htab,
 	debug("INSERT: done\n");
 	return 1;		/* everything OK */
 }
+
+/*
+ * hwalk_r()
+ */
+
+/*
+ * Walk all of the entries in the hash, calling the callback for each one.
+ * this allows some generic operation to be performed on each element.
+ */
+int hwalk_r(struct hsearch_data *htab, int (*callback)(ENTRY *))
+{
+	int i;
+	int retval;
+
+	for (i = 1; i <= htab->size; ++i) {
+		if (htab->table[i].used > 0) {
+			retval = callback(&htab->table[i].entry);
+			if (retval)
+				return retval;
+		}
+	}
+
+	return 0;
+}
-- 
1.7.11.5

^ permalink raw reply related	[flat|nested] 124+ messages in thread

* [U-Boot] [PATCH v5 08/20] env: Add a command to view callbacks
  2012-12-12  4:16                                           ` [U-Boot] [PATCH v5 " Joe Hershberger
                                                               ` (6 preceding siblings ...)
  2012-12-12  4:16                                             ` [U-Boot] [PATCH v5 07/20] env: Add support for callbacks to environment vars Joe Hershberger
@ 2012-12-12  4:16                                             ` Joe Hershberger
  2012-12-12  4:16                                             ` [U-Boot] [PATCH v5 09/20] env: Add a bootfile env handler Joe Hershberger
                                                               ` (12 subsequent siblings)
  20 siblings, 0 replies; 124+ messages in thread
From: Joe Hershberger @ 2012-12-12  4:16 UTC (permalink / raw)
  To: u-boot

The callbacks can be bound, but are otherwise invisible.  Add a command
to show what callbacks are available.

Signed-off-by: Joe Hershberger <joe.hershberger@ni.com>

!!! fix callback command
---
Changes in v5:
- Fixed callbacks command help
- Compare current callback against pre-relocation address manually

Changes in v4: None
Changes in v3: None
Changes in v2: None

 README              |  1 +
 common/cmd_nvedit.c | 81 +++++++++++++++++++++++++++++++++++++++++++++++++++++
 2 files changed, 82 insertions(+)

diff --git a/README b/README
index 6b1698c..e8b7b8b 100644
--- a/README
+++ b/README
@@ -810,6 +810,7 @@ The following options need to be configured:
 		CONFIG_CMD_EDITENV	  edit env variable
 		CONFIG_CMD_EEPROM	* EEPROM read/write support
 		CONFIG_CMD_ELF		* bootelf, bootvx
+		CONFIG_CMD_ENV_CALLBACK	* display details about env callbacks
 		CONFIG_CMD_EXPORTENV	* export the environment
 		CONFIG_CMD_EXT2		* ext2 command support
 		CONFIG_CMD_EXT4		* ext4 command support
diff --git a/common/cmd_nvedit.c b/common/cmd_nvedit.c
index 022ad39..1e51b9d 100644
--- a/common/cmd_nvedit.c
+++ b/common/cmd_nvedit.c
@@ -514,6 +514,81 @@ int do_env_ask(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
 }
 #endif
 
+#if defined(CONFIG_CMD_ENV_CALLBACK)
+static int print_static_binding(const char *var_name, const char *callback_name)
+{
+	printf("\t%-20s %-20s\n", var_name, callback_name);
+
+	return 0;
+}
+
+static int print_active_callback(ENTRY *entry)
+{
+	struct env_clbk_tbl *clbkp;
+	int i;
+	int num_callbacks;
+
+	if (entry->callback == NULL)
+		return 0;
+
+	/* look up the callback in the linker-list */
+	num_callbacks = ll_entry_count(struct env_clbk_tbl, env_clbk);
+	for (i = 0, clbkp = ll_entry_start(struct env_clbk_tbl, env_clbk);
+	     i < num_callbacks;
+	     i++, clbkp++) {
+#if defined(CONFIG_NEEDS_MANUAL_RELOC)
+		if (entry->callback == clbkp->callback + gd->reloc_off)
+#else
+		if (entry->callback == clbkp->callback)
+#endif
+			break;
+	}
+
+	if (i == num_callbacks)
+		/* this should probably never happen, but just in case... */
+		printf("\t%-20s %p\n", entry->key, entry->callback);
+	else
+		printf("\t%-20s %-20s\n", entry->key, clbkp->name);
+
+	return 0;
+}
+
+/*
+ * Print the callbacks available and what they are bound to
+ */
+int do_env_callback(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
+{
+	struct env_clbk_tbl *clbkp;
+	int i;
+	int num_callbacks;
+
+	/* Print the available callbacks */
+	puts("Available callbacks:\n");
+	puts("\tCallback Name\n");
+	puts("\t-------------\n");
+	num_callbacks = ll_entry_count(struct env_clbk_tbl, env_clbk);
+	for (i = 0, clbkp = ll_entry_start(struct env_clbk_tbl, env_clbk);
+	     i < num_callbacks;
+	     i++, clbkp++)
+		printf("\t%s\n", clbkp->name);
+	puts("\n");
+
+	/* Print the static bindings that may exist */
+	puts("Static callback bindings:\n");
+	printf("\t%-20s %-20s\n", "Variable Name", "Callback Name");
+	printf("\t%-20s %-20s\n", "-------------", "-------------");
+	env_attr_walk(ENV_CALLBACK_LIST_STATIC, print_static_binding);
+	puts("\n");
+
+	/* walk through each variable and print the callback if it has one */
+	puts("Active callback bindings:\n");
+	printf("\t%-20s %-20s\n", "Variable Name", "Callback Name");
+	printf("\t%-20s %-20s\n", "-------------", "-------------");
+	hwalk_r(&env_htab, print_active_callback);
+	return 0;
+}
+#endif
+
 /*
  * Interactively edit an environment variable
  */
@@ -981,6 +1056,9 @@ static cmd_tbl_t cmd_env_sub[] = {
 #if defined(CONFIG_CMD_EDITENV)
 	U_BOOT_CMD_MKENT(edit, 2, 0, do_env_edit, "", ""),
 #endif
+#if defined(CONFIG_CMD_ENV_CALLBACK)
+	U_BOOT_CMD_MKENT(callbacks, 1, 0, do_env_callback, "", ""),
+#endif
 #if defined(CONFIG_CMD_EXPORTENV)
 	U_BOOT_CMD_MKENT(export, 4, 0, do_env_export, "", ""),
 #endif
@@ -1031,6 +1109,9 @@ static char env_help_text[] =
 #if defined(CONFIG_CMD_ASKENV)
 	"ask name [message] [size] - ask for environment variable\nenv "
 #endif
+#if defined(CONFIG_CMD_ENV_CALLBACK)
+	"callbacks - print callbacks and their associated variables\nenv "
+#endif
 	"default [-f] -a - [forcibly] reset default environment\n"
 	"env default [-f] var [...] - [forcibly] reset variable(s) to their default values\n"
 #if defined(CONFIG_CMD_EDITENV)
-- 
1.7.11.5

^ permalink raw reply related	[flat|nested] 124+ messages in thread

* [U-Boot] [PATCH v5 09/20] env: Add a bootfile env handler
  2012-12-12  4:16                                           ` [U-Boot] [PATCH v5 " Joe Hershberger
                                                               ` (7 preceding siblings ...)
  2012-12-12  4:16                                             ` [U-Boot] [PATCH v5 08/20] env: Add a command to view callbacks Joe Hershberger
@ 2012-12-12  4:16                                             ` Joe Hershberger
  2012-12-12  4:16                                             ` [U-Boot] [PATCH v5 10/20] env: Add a baudrate " Joe Hershberger
                                                               ` (11 subsequent siblings)
  20 siblings, 0 replies; 124+ messages in thread
From: Joe Hershberger @ 2012-12-12  4:16 UTC (permalink / raw)
  To: u-boot

Remove the hard-coded bootfile handler and use a callback instead

Signed-off-by: Joe Hershberger <joe.hershberger@ni.com>
---
Changes in v5: None
Changes in v4: None
Changes in v3: None
Changes in v2: None

 common/cmd_nvedit.c    |  9 ---------
 include/env_callback.h |  1 +
 net/net.c              | 17 +++++++++++++++++
 3 files changed, 18 insertions(+), 9 deletions(-)

diff --git a/common/cmd_nvedit.c b/common/cmd_nvedit.c
index 1e51b9d..874baef 100644
--- a/common/cmd_nvedit.c
+++ b/common/cmd_nvedit.c
@@ -50,9 +50,6 @@
 #include <serial.h>
 #include <linux/stddef.h>
 #include <asm/byteorder.h>
-#if defined(CONFIG_CMD_NET)
-#include <net.h>
-#endif
 
 DECLARE_GLOBAL_DATA_PTR;
 
@@ -328,12 +325,6 @@ int env_change_ok(const ENTRY *item, const char *newval, enum env_op op,
 		load_addr = simple_strtoul(newval, NULL, 16);
 		return 0;
 	}
-#if defined(CONFIG_CMD_NET)
-	else if (strcmp(name, "bootfile") == 0) {
-		copy_filename(BootFile, newval, sizeof(BootFile));
-		return 0;
-	}
-#endif
 	return 0;
 }
 
diff --git a/include/env_callback.h b/include/env_callback.h
index 5a460f3..bce0136 100644
--- a/include/env_callback.h
+++ b/include/env_callback.h
@@ -39,6 +39,7 @@
  * a new association in the ".callbacks" environment variable.
  */
 #define ENV_CALLBACK_LIST_STATIC ENV_CALLBACK_VAR ":callbacks," \
+	"bootfile:bootfile," \
 	CONFIG_ENV_CALLBACK_LIST_STATIC
 
 struct env_clbk_tbl {
diff --git a/net/net.c b/net/net.c
index da68a61..a40cde1 100644
--- a/net/net.c
+++ b/net/net.c
@@ -82,6 +82,7 @@
 
 #include <common.h>
 #include <command.h>
+#include <environment.h>
 #include <net.h>
 #if defined(CONFIG_STATUS_LED)
 #include <miiphy.h>
@@ -208,6 +209,22 @@ static int NetTryCount;
 
 /**********************************************************************/
 
+static int on_bootfile(const char *name, const char *value, enum env_op op,
+	int flags)
+{
+	switch (op) {
+	case env_op_create:
+	case env_op_overwrite:
+		copy_filename(BootFile, value, sizeof(BootFile));
+		break;
+	default:
+		break;
+	}
+
+	return 0;
+}
+U_BOOT_ENV_CALLBACK(bootfile, on_bootfile);
+
 /*
  * Check if autoload is enabled. If so, use either NFS or TFTP to download
  * the boot file.
-- 
1.7.11.5

^ permalink raw reply related	[flat|nested] 124+ messages in thread

* [U-Boot] [PATCH v5 10/20] env: Add a baudrate env handler
  2012-12-12  4:16                                           ` [U-Boot] [PATCH v5 " Joe Hershberger
                                                               ` (8 preceding siblings ...)
  2012-12-12  4:16                                             ` [U-Boot] [PATCH v5 09/20] env: Add a bootfile env handler Joe Hershberger
@ 2012-12-12  4:16                                             ` Joe Hershberger
  2012-12-12  4:16                                             ` [U-Boot] [PATCH v5 11/20] env: Add a loadaddr " Joe Hershberger
                                                               ` (10 subsequent siblings)
  20 siblings, 0 replies; 124+ messages in thread
From: Joe Hershberger @ 2012-12-12  4:16 UTC (permalink / raw)
  To: u-boot

Remove the hard-coded baudrate handler and use a callback instead

Signed-off-by: Joe Hershberger <joe.hershberger@ni.com>
---
Changes in v5: None
Changes in v4: None
Changes in v3: None
Changes in v2: None

 common/cmd_nvedit.c     | 47 ---------------------------------
 drivers/serial/serial.c | 70 +++++++++++++++++++++++++++++++++++++++++++++++++
 include/env_callback.h  |  1 +
 3 files changed, 71 insertions(+), 47 deletions(-)

diff --git a/common/cmd_nvedit.c b/common/cmd_nvedit.c
index 874baef..df136cf 100644
--- a/common/cmd_nvedit.c
+++ b/common/cmd_nvedit.c
@@ -78,12 +78,6 @@ ulong save_addr;			/* Default Save Address */
 ulong save_size;			/* Default Save Size (in bytes) */
 
 /*
- * Table with supported baudrates (defined in config_xyz.h)
- */
-static const unsigned long baudrate_table[] = CONFIG_SYS_BAUDRATE_TABLE;
-#define	N_BAUDRATES (sizeof(baudrate_table) / sizeof(baudrate_table[0]))
-
-/*
  * This variable is incremented on each do_env_set(), so it can
  * be used via get_env_id() as an indication, if the environment
  * has changed or not. So it is possible to reread an environment
@@ -275,47 +269,6 @@ int env_change_ok(const ENTRY *item, const char *newval, enum env_op op,
 		}
 	}
 #endif
-	/*
-	 * When we change baudrate, or we are doing an env default -a
-	 * (which will erase all variables prior to calling this),
-	 * we want the baudrate to actually change - for real.
-	 */
-	if (op != env_op_create ||		/* variable exists */
-		(flag & H_NOCLEAR) == 0) {	/* or env is clear */
-		/*
-		 * Switch to new baudrate if new baudrate is supported
-		 */
-		if (strcmp(name, "baudrate") == 0) {
-			int baudrate = simple_strtoul(newval, NULL, 10);
-			int i;
-			for (i = 0; i < N_BAUDRATES; ++i) {
-				if (baudrate == baudrate_table[i])
-					break;
-			}
-			if (i == N_BAUDRATES) {
-				if ((flag & H_FORCE) == 0)
-					printf("## Baudrate %d bps not "
-						"supported\n", 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);
-			gd->baudrate = baudrate;
-#if defined(CONFIG_PPC) || defined(CONFIG_MCF52x2)
-			gd->bd->bi_baudrate = baudrate;
-#endif
-
-			serial_setbrg();
-			udelay(50000);
-			while (getc() != '\r')
-				;
-		}
-	}
 
 	/*
 	 * Some variables should be updated when the corresponding
diff --git a/drivers/serial/serial.c b/drivers/serial/serial.c
index f5f43a6..1f8955a 100644
--- a/drivers/serial/serial.c
+++ b/drivers/serial/serial.c
@@ -22,6 +22,7 @@
  */
 
 #include <common.h>
+#include <environment.h>
 #include <serial.h>
 #include <stdio_dev.h>
 #include <post.h>
@@ -32,6 +33,11 @@ DECLARE_GLOBAL_DATA_PTR;
 
 static struct serial_device *serial_devices;
 static struct serial_device *serial_current;
+/*
+ * Table with supported baudrates (defined in config_xyz.h)
+ */
+static const unsigned long baudrate_table[] = CONFIG_SYS_BAUDRATE_TABLE;
+#define	N_BAUDRATES (sizeof(baudrate_table) / sizeof(baudrate_table[0]))
 
 /**
  * serial_null() - Void registration routine of a serial driver
@@ -46,6 +52,70 @@ static void serial_null(void)
 }
 
 /**
+ * on_baudrate() - Update the actual baudrate when the env var changes
+ *
+ * This will check for a valid baudrate and only apply it if valid.
+ */
+static int on_baudrate(const char *name, const char *value, enum env_op op,
+	int flags)
+{
+	int i;
+	int baudrate;
+
+	switch (op) {
+	case env_op_create:
+	case env_op_overwrite:
+		/*
+		 * Switch to new baudrate if new baudrate is supported
+		 */
+		baudrate = simple_strtoul(value, NULL, 10);
+
+		/* Not actually changing */
+		if (gd->baudrate == baudrate)
+			return 0;
+
+		for (i = 0; i < N_BAUDRATES; ++i) {
+			if (baudrate == baudrate_table[i])
+				break;
+		}
+		if (i == N_BAUDRATES) {
+			if ((flags & H_FORCE) == 0)
+				printf("## Baudrate %d bps not supported\n",
+					baudrate);
+			return 1;
+		}
+		if ((flags & H_INTERACTIVE) != 0) {
+			printf("## Switch baudrate to %d"
+				" bps and press ENTER ...\n", baudrate);
+			udelay(50000);
+		}
+
+		gd->baudrate = baudrate;
+#if defined(CONFIG_PPC) || defined(CONFIG_MCF52x2)
+		gd->bd->bi_baudrate = baudrate;
+#endif
+
+		serial_setbrg();
+
+		udelay(50000);
+
+		if ((flags & H_INTERACTIVE) != 0)
+			while (1) {
+				if (getc() == '\r')
+					break;
+			}
+
+		return 0;
+	case env_op_delete:
+		printf("## Baudrate may not be deleted\n");
+		return 1;
+	default:
+		return 0;
+	}
+}
+U_BOOT_ENV_CALLBACK(baudrate, on_baudrate);
+
+/**
  * serial_initfunc() - Forward declare of driver registration routine
  * @name:	Name of the real driver registration routine.
  *
diff --git a/include/env_callback.h b/include/env_callback.h
index bce0136..2f5048f 100644
--- a/include/env_callback.h
+++ b/include/env_callback.h
@@ -39,6 +39,7 @@
  * a new association in the ".callbacks" environment variable.
  */
 #define ENV_CALLBACK_LIST_STATIC ENV_CALLBACK_VAR ":callbacks," \
+	"baudrate:baudrate," \
 	"bootfile:bootfile," \
 	CONFIG_ENV_CALLBACK_LIST_STATIC
 
-- 
1.7.11.5

^ permalink raw reply related	[flat|nested] 124+ messages in thread

* [U-Boot] [PATCH v5 11/20] env: Add a loadaddr env handler
  2012-12-12  4:16                                           ` [U-Boot] [PATCH v5 " Joe Hershberger
                                                               ` (9 preceding siblings ...)
  2012-12-12  4:16                                             ` [U-Boot] [PATCH v5 10/20] env: Add a baudrate " Joe Hershberger
@ 2012-12-12  4:16                                             ` Joe Hershberger
  2012-12-12  4:16                                             ` [U-Boot] [PATCH v5 12/20] env: Add a console " Joe Hershberger
                                                               ` (9 subsequent siblings)
  20 siblings, 0 replies; 124+ messages in thread
From: Joe Hershberger @ 2012-12-12  4:16 UTC (permalink / raw)
  To: u-boot

Remove the hard-coded loadaddr handler and use a callback instead

Signed-off-by: Joe Hershberger <joe.hershberger@ni.com>
---
Changes in v5: None
Changes in v4: None
Changes in v3: None
Changes in v2: None

 common/cmd_nvedit.c    | 12 ------------
 common/image.c         | 21 +++++++++++++++++++++
 include/env_callback.h |  1 +
 3 files changed, 22 insertions(+), 12 deletions(-)

diff --git a/common/cmd_nvedit.c b/common/cmd_nvedit.c
index df136cf..9ff8b36 100644
--- a/common/cmd_nvedit.c
+++ b/common/cmd_nvedit.c
@@ -73,10 +73,6 @@ SPI_FLASH|NVRAM|MMC|FAT|REMOTE} or CONFIG_ENV_IS_NOWHERE
  */
 #define	MAX_ENV_SIZE	(1 << 20)	/* 1 MiB */
 
-ulong load_addr = CONFIG_SYS_LOAD_ADDR;	/* Default Load Address */
-ulong save_addr;			/* Default Save Address */
-ulong save_size;			/* Default Save Size (in bytes) */
-
 /*
  * This variable is incremented on each do_env_set(), so it can
  * be used via get_env_id() as an indication, if the environment
@@ -270,14 +266,6 @@ int env_change_ok(const ENTRY *item, const char *newval, enum env_op op,
 	}
 #endif
 
-	/*
-	 * Some variables should be updated when the corresponding
-	 * entry in the environment is changed
-	 */
-	if (strcmp(name, "loadaddr") == 0) {
-		load_addr = simple_strtoul(newval, NULL, 16);
-		return 0;
-	}
 	return 0;
 }
 
diff --git a/common/image.c b/common/image.c
index 69e888c..95498e6 100644
--- a/common/image.c
+++ b/common/image.c
@@ -43,6 +43,7 @@
 #include <rtc.h>
 #endif
 
+#include <environment.h>
 #include <image.h>
 
 #if defined(CONFIG_FIT) || defined(CONFIG_OF_LIBFDT)
@@ -416,6 +417,26 @@ static const image_header_t *image_get_ramdisk(ulong rd_addr, uint8_t arch,
 /* Shared dual-format routines */
 /*****************************************************************************/
 #ifndef USE_HOSTCC
+ulong load_addr = CONFIG_SYS_LOAD_ADDR;	/* Default Load Address */
+ulong save_addr;			/* Default Save Address */
+ulong save_size;			/* Default Save Size (in bytes) */
+
+static int on_loadaddr(const char *name, const char *value, enum env_op op,
+	int flags)
+{
+	switch (op) {
+	case env_op_create:
+	case env_op_overwrite:
+		load_addr = simple_strtoul(value, NULL, 16);
+		break;
+	default:
+		break;
+	}
+
+	return 0;
+}
+U_BOOT_ENV_CALLBACK(loadaddr, on_loadaddr);
+
 ulong getenv_bootm_low(void)
 {
 	char *s = getenv("bootm_low");
diff --git a/include/env_callback.h b/include/env_callback.h
index 2f5048f..bb398ec 100644
--- a/include/env_callback.h
+++ b/include/env_callback.h
@@ -41,6 +41,7 @@
 #define ENV_CALLBACK_LIST_STATIC ENV_CALLBACK_VAR ":callbacks," \
 	"baudrate:baudrate," \
 	"bootfile:bootfile," \
+	"loadaddr:loadaddr," \
 	CONFIG_ENV_CALLBACK_LIST_STATIC
 
 struct env_clbk_tbl {
-- 
1.7.11.5

^ permalink raw reply related	[flat|nested] 124+ messages in thread

* [U-Boot] [PATCH v5 12/20] env: Add a console env handler
  2012-12-12  4:16                                           ` [U-Boot] [PATCH v5 " Joe Hershberger
                                                               ` (10 preceding siblings ...)
  2012-12-12  4:16                                             ` [U-Boot] [PATCH v5 11/20] env: Add a loadaddr " Joe Hershberger
@ 2012-12-12  4:16                                             ` Joe Hershberger
  2012-12-12  4:16                                             ` [U-Boot] [PATCH v5 13/20] env: Add a silent " Joe Hershberger
                                                               ` (8 subsequent siblings)
  20 siblings, 0 replies; 124+ messages in thread
From: Joe Hershberger @ 2012-12-12  4:16 UTC (permalink / raw)
  To: u-boot

Remove the hard-coded console handler and use a callback instead

Signed-off-by: Joe Hershberger <joe.hershberger@ni.com>
---
Changes in v5: None
Changes in v4: None
Changes in v3: None
Changes in v2: None

 common/cmd_nvedit.c    | 36 +++---------------------------------
 common/console.c       | 44 ++++++++++++++++++++++++++++++++++++++++++++
 include/env_callback.h |  1 +
 3 files changed, 48 insertions(+), 33 deletions(-)

diff --git a/common/cmd_nvedit.c b/common/cmd_nvedit.c
index 9ff8b36..cb191cd 100644
--- a/common/cmd_nvedit.c
+++ b/common/cmd_nvedit.c
@@ -47,7 +47,6 @@
 #include <errno.h>
 #include <malloc.h>
 #include <watchdog.h>
-#include <serial.h>
 #include <linux/stddef.h>
 #include <asm/byteorder.h>
 
@@ -206,10 +205,9 @@ static int do_env_grep(cmd_tbl_t *cmdtp, int flag,
 int env_change_ok(const ENTRY *item, const char *newval, enum env_op op,
 	int flag)
 {
-	int   console = -1;
+#ifndef CONFIG_ENV_OVERWRITE
 	const char *name;
-#if !defined(CONFIG_ENV_OVERWRITE) && defined(CONFIG_OVERWRITE_ETHADDR_ONCE) \
-&& defined(CONFIG_ETHADDR)
+#if defined(CONFIG_OVERWRITE_ETHADDR_ONCE) && defined(CONFIG_ETHADDR)
 	const char *oldval = NULL;
 
 	if (op != env_op_create)
@@ -217,35 +215,7 @@ int env_change_ok(const ENTRY *item, const char *newval, enum env_op op,
 #endif
 
 	name = item->key;
-
-	/* Default value for NULL to protect string-manipulating functions */
-	newval = newval ? : "";
-
-	/* Check for console redirection */
-	if (strcmp(name, "stdin") == 0)
-		console = stdin;
-	else if (strcmp(name, "stdout") == 0)
-		console = stdout;
-	else if (strcmp(name, "stderr") == 0)
-		console = stderr;
-
-	if (console != -1 && (gd->flags & GD_FLG_DEVINIT) != 0) {
-		if ((newval == NULL) || (*newval == '\0')) {
-			/* We cannot delete stdin/stdout/stderr */
-			if ((flag & H_FORCE) == 0)
-				printf("Can't delete \"%s\"\n", name);
-			return 1;
-		}
-
-#ifdef CONFIG_CONSOLE_MUX
-		if (iomux_doenv(console, newval))
-			return 1;
-#else
-		/* Try assigning specified device */
-		if (console_assign(console, newval) < 0)
-			return 1;
-#endif /* CONFIG_CONSOLE_MUX */
-	}
+#endif
 
 #ifndef CONFIG_ENV_OVERWRITE
 	/*
diff --git a/common/console.c b/common/console.c
index 880acd9..549d379 100644
--- a/common/console.c
+++ b/common/console.c
@@ -24,11 +24,55 @@
 #include <common.h>
 #include <stdarg.h>
 #include <malloc.h>
+#include <serial.h>
 #include <stdio_dev.h>
 #include <exports.h>
+#include <environment.h>
 
 DECLARE_GLOBAL_DATA_PTR;
 
+static int on_console(const char *name, const char *value, enum env_op op,
+	int flags)
+{
+	int console = -1;
+
+	/* Check for console redirection */
+	if (strcmp(name, "stdin") == 0)
+		console = stdin;
+	else if (strcmp(name, "stdout") == 0)
+		console = stdout;
+	else if (strcmp(name, "stderr") == 0)
+		console = stderr;
+
+	/* if not actually setting a console variable, we don't care */
+	if (console == -1 || (gd->flags & GD_FLG_DEVINIT) == 0)
+		return 0;
+
+	switch (op) {
+	case env_op_create:
+	case env_op_overwrite:
+
+#ifdef CONFIG_CONSOLE_MUX
+		if (iomux_doenv(console, value))
+			return 1;
+#else
+		/* Try assigning specified device */
+		if (console_assign(console, value) < 0)
+			return 1;
+#endif /* CONFIG_CONSOLE_MUX */
+		return 0;
+
+	case env_op_delete:
+		if ((flags & H_FORCE) == 0)
+			printf("Can't delete \"%s\"\n", name);
+		return 1;
+
+	default:
+		return 0;
+	}
+}
+U_BOOT_ENV_CALLBACK(console, on_console);
+
 #ifdef CONFIG_SYS_CONSOLE_IS_IN_ENV
 /*
  * if overwrite_console returns 1, the stdin, stderr and stdout
diff --git a/include/env_callback.h b/include/env_callback.h
index bb398ec..9d2d2c9 100644
--- a/include/env_callback.h
+++ b/include/env_callback.h
@@ -42,6 +42,7 @@
 	"baudrate:baudrate," \
 	"bootfile:bootfile," \
 	"loadaddr:loadaddr," \
+	"stdin:console,stdout:console,stderr:console," \
 	CONFIG_ENV_CALLBACK_LIST_STATIC
 
 struct env_clbk_tbl {
-- 
1.7.11.5

^ permalink raw reply related	[flat|nested] 124+ messages in thread

* [U-Boot] [PATCH v5 13/20] env: Add a silent env handler
  2012-12-12  4:16                                           ` [U-Boot] [PATCH v5 " Joe Hershberger
                                                               ` (11 preceding siblings ...)
  2012-12-12  4:16                                             ` [U-Boot] [PATCH v5 12/20] env: Add a console " Joe Hershberger
@ 2012-12-12  4:16                                             ` Joe Hershberger
  2012-12-12  4:16                                             ` [U-Boot] [PATCH v5 14/20] env: Add environment variable flags Joe Hershberger
                                                               ` (7 subsequent siblings)
  20 siblings, 0 replies; 124+ messages in thread
From: Joe Hershberger @ 2012-12-12  4:16 UTC (permalink / raw)
  To: u-boot

The silent variable now updates the global data flag anytime it is
changed as well as after the env relocation (in case its value is
different from the default env in such cases as NAND env)

Signed-off-by: Joe Hershberger <joe.hershberger@ni.com>
---
Changes in v5: None
Changes in v4: None
Changes in v3: None
Changes in v2: None

 common/console.c       | 23 +++++++++++++++++++++++
 doc/README.silent      | 14 ++++++++++----
 include/env_callback.h |  7 +++++++
 3 files changed, 40 insertions(+), 4 deletions(-)

diff --git a/common/console.c b/common/console.c
index 549d379..3322bcc 100644
--- a/common/console.c
+++ b/common/console.c
@@ -73,6 +73,29 @@ static int on_console(const char *name, const char *value, enum env_op op,
 }
 U_BOOT_ENV_CALLBACK(console, on_console);
 
+#ifdef CONFIG_SILENT_CONSOLE
+static int on_silent(const char *name, const char *value, enum env_op op,
+	int flags)
+{
+#ifndef CONFIG_SILENT_CONSOLE_UPDATE_ON_SET
+	if (flags & H_INTERACTIVE)
+		return 0;
+#endif
+#ifndef CONFIG_SILENT_CONSOLE_UPDATE_ON_RELOC
+	if ((flags & H_INTERACTIVE) == 0)
+		return 0;
+#endif
+
+	if (value != NULL)
+		gd->flags |= GD_FLG_SILENT;
+	else
+		gd->flags &= ~GD_FLG_SILENT;
+
+	return 0;
+}
+U_BOOT_ENV_CALLBACK(silent, on_silent);
+#endif
+
 #ifdef CONFIG_SYS_CONSOLE_IS_IN_ENV
 /*
  * if overwrite_console returns 1, the stdin, stderr and stdout
diff --git a/doc/README.silent b/doc/README.silent
index a26e3df..70202ce 100644
--- a/doc/README.silent
+++ b/doc/README.silent
@@ -1,9 +1,15 @@
 The config option CONFIG_SILENT_CONSOLE can be used to quiet messages
 on the console.  If the option has been enabled, the output can be
-silenced by setting the environment variable "silent".  The variable
-is latched into the global data at an early stage in the boot process
-so deleting it with "setenv" will not take effect until the system is
-restarted.
+silenced by setting the environment variable "silent".
+
+- CONFIG_SILENT_CONSOLE_UPDATE_ON_SET
+	When the "silent" variable is changed with env set, the change
+	will take effect immediately.
+
+- CONFIG_SILENT_CONSOLE_UPDATE_ON_RELOC
+	Some environments are not available until relocation (e.g. NAND)
+	so this will make the value in the flash env take effect at
+	relocation.
 
 The following actions are taken if "silent" is set at boot time:
 
diff --git a/include/env_callback.h b/include/env_callback.h
index 9d2d2c9..f52e133 100644
--- a/include/env_callback.h
+++ b/include/env_callback.h
@@ -34,6 +34,12 @@
 #define CONFIG_ENV_CALLBACK_LIST_STATIC
 #endif
 
+#ifdef CONFIG_SILENT_CONSOLE
+#define SILENT_CALLBACK "silent:silent,"
+#else
+#define SILENT_CALLBACK
+#endif
+
 /*
  * This list of callback bindings is static, but may be overridden by defining
  * a new association in the ".callbacks" environment variable.
@@ -42,6 +48,7 @@
 	"baudrate:baudrate," \
 	"bootfile:bootfile," \
 	"loadaddr:loadaddr," \
+	SILENT_CALLBACK \
 	"stdin:console,stdout:console,stderr:console," \
 	CONFIG_ENV_CALLBACK_LIST_STATIC
 
-- 
1.7.11.5

^ permalink raw reply related	[flat|nested] 124+ messages in thread

* [U-Boot] [PATCH v5 14/20] env: Add environment variable flags
  2012-12-12  4:16                                           ` [U-Boot] [PATCH v5 " Joe Hershberger
                                                               ` (12 preceding siblings ...)
  2012-12-12  4:16                                             ` [U-Boot] [PATCH v5 13/20] env: Add a silent " Joe Hershberger
@ 2012-12-12  4:16                                             ` Joe Hershberger
  2012-12-12  4:16                                             ` [U-Boot] [PATCH v5 15/20] tools/env: Add environment variable flags support Joe Hershberger
                                                               ` (6 subsequent siblings)
  20 siblings, 0 replies; 124+ messages in thread
From: Joe Hershberger @ 2012-12-12  4:16 UTC (permalink / raw)
  To: u-boot

Currently just validates variable types as decimal, hexidecimal,
boolean, ip address, and mac address.

If the entry is not found in the env ".flags", then look in the static
one. This allows the env to override the static definitions, but prevents
the need to have every definition in the environment distracting you.

Signed-off-by: Joe Hershberger <joe.hershberger@ni.com>
---
Changes in v5:
- Fixed out-of-bounds array access in env_flags_parse_vartype()

Changes in v4: None
Changes in v3: None
Changes in v2: None

 README                 |  37 ++++++
 common/Makefile        |   2 +
 common/cmd_nvedit.c    |  50 +-------
 common/env_common.c    |   2 +-
 common/env_flags.c     | 319 +++++++++++++++++++++++++++++++++++++++++++++++++
 include/env_callback.h |   2 +
 include/env_default.h  |   3 +
 include/env_flags.h    |  76 ++++++++++++
 include/environment.h  |   9 +-
 include/search.h       |   1 +
 lib/hashtable.c        |   4 +
 11 files changed, 447 insertions(+), 58 deletions(-)
 create mode 100644 common/env_flags.c
 create mode 100644 include/env_flags.h

diff --git a/README b/README
index e8b7b8b..5705925 100644
--- a/README
+++ b/README
@@ -2168,6 +2168,11 @@ CBFS (Coreboot Filesystem) support
 		serial# is unaffected by this, i. e. it remains
 		read-only.]
 
+		The same can be accomplished in a more flexible way
+		for any variable by configuring the type of access
+		to allow for those variables in the ".flags" variable
+		or define CONFIG_ENV_FLAGS_LIST_STATIC.
+
 - Protected RAM:
 		CONFIG_PRAM
 
@@ -3068,6 +3073,38 @@ Configuration Settings:
 	cases. This setting can be used to tune behaviour; see
 	lib/hashtable.c for details.
 
+- CONFIG_ENV_FLAGS_LIST_DEFAULT
+- CONFIG_ENV_FLAGS_LIST_STATIC
+	Enable validation of the values given to enviroment variables when
+	calling env set.  Variables can be restricted to only decimal,
+	hexadecimal, or boolean.  If CONFIG_CMD_NET is also defined,
+	the variables can also be restricted to IP address or MAC address.
+
+	The format of the list is:
+		type_attribute = [s|d|x|b|i|m]
+		attributes = type_attribute
+		entry = variable_name[:attributes]
+		list = entry[,list]
+
+	The type attributes are:
+		s - String (default)
+		d - Decimal
+		x - Hexadecimal
+		b - Boolean ([1yYtT|0nNfF])
+		i - IP address
+		m - MAC address
+
+	- CONFIG_ENV_FLAGS_LIST_DEFAULT
+		Define this to a list (string) to define the ".flags"
+		envirnoment variable in the default or embedded environment.
+
+	- CONFIG_ENV_FLAGS_LIST_STATIC
+		Define this to a list (string) to define validation that
+		should be done if an entry is not found in the ".flags"
+		environment variable.  To override a setting in the static
+		list, simply add an entry for the same variable name to the
+		".flags" variable.
+
 The following definitions that deal with the placement and management
 of environment data (variable area); in general, we support the
 following configurations:
diff --git a/common/Makefile b/common/Makefile
index af6e8f9..ef2bd00 100644
--- a/common/Makefile
+++ b/common/Makefile
@@ -46,6 +46,7 @@ COBJS-y += cmd_version.o
 COBJS-y += env_attr.o
 COBJS-y += env_callback.o
 COBJS-y += env_common.o
+COBJS-y += env_flags.o
 COBJS-$(CONFIG_ENV_IS_IN_DATAFLASH) += env_dataflash.o
 COBJS-$(CONFIG_ENV_IS_IN_EEPROM) += env_eeprom.o
 XCOBJS-$(CONFIG_ENV_IS_EMBEDDED) += env_embedded.o
@@ -202,6 +203,7 @@ COBJS-$(CONFIG_SPL_NET_SUPPORT) += cmd_nvedit.o
 COBJS-$(CONFIG_SPL_NET_SUPPORT) += env_attr.o
 COBJS-$(CONFIG_SPL_NET_SUPPORT) += env_callback.o
 COBJS-$(CONFIG_SPL_NET_SUPPORT) += env_common.o
+COBJS-$(CONFIG_SPL_NET_SUPPORT) += env_flags.o
 COBJS-$(CONFIG_SPL_NET_SUPPORT) += env_nowhere.o
 COBJS-$(CONFIG_SPL_NET_SUPPORT) += miiphyutil.o
 endif
diff --git a/common/cmd_nvedit.c b/common/cmd_nvedit.c
index cb191cd..f645194 100644
--- a/common/cmd_nvedit.c
+++ b/common/cmd_nvedit.c
@@ -192,57 +192,9 @@ static int do_env_grep(cmd_tbl_t *cmdtp, int flag,
 #endif /* CONFIG_SPL_BUILD */
 
 /*
- * Perform 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 instead.
- * Also called as a callback function by himport_r().
- * Returns 0 in case of success, 1 in case of failure.
- * When (flag & H_FORCE) is set, do not print out any error message and force
- * overwriting of write-once variables.
- */
-
-int env_change_ok(const ENTRY *item, const char *newval, enum env_op op,
-	int flag)
-{
-#ifndef CONFIG_ENV_OVERWRITE
-	const char *name;
-#if defined(CONFIG_OVERWRITE_ETHADDR_ONCE) && defined(CONFIG_ETHADDR)
-	const char *oldval = NULL;
-
-	if (op != env_op_create)
-		oldval = item->data;
-#endif
-
-	name = item->key;
-#endif
-
-#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
-
-	return 0;
-}
-
-/*
  * Set a new environment variable,
  * or replace or delete an existing one.
-*/
+ */
 static int _do_env_set(int flag, int argc, char * const argv[])
 {
 	int   i, len;
diff --git a/common/env_common.c b/common/env_common.c
index 067fe3f..bb18070 100644
--- a/common/env_common.c
+++ b/common/env_common.c
@@ -40,7 +40,7 @@ DECLARE_GLOBAL_DATA_PTR;
 #include <env_default.h>
 
 struct hsearch_data env_htab = {
-	.change_ok = env_change_ok,
+	.change_ok = env_flags_validate,
 };
 
 static uchar __env_get_char_spec(int index)
diff --git a/common/env_flags.c b/common/env_flags.c
new file mode 100644
index 0000000..a58d614
--- /dev/null
+++ b/common/env_flags.c
@@ -0,0 +1,319 @@
+/*
+ * (C) Copyright 2012
+ * Joe Hershberger, National Instruments, joe.hershberger at 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
+ */
+
+#include <linux/string.h>
+#include <linux/ctype.h>
+
+#include <common.h>
+#include <environment.h>
+
+#ifdef CONFIG_CMD_NET
+#define ENV_FLAGS_NET_VARTYPE_REPS "im"
+#else
+#define ENV_FLAGS_NET_VARTYPE_REPS ""
+#endif
+
+static const char env_flags_vartype_rep[] = "sdxb" ENV_FLAGS_NET_VARTYPE_REPS;
+
+/*
+ * Parse the flags string from a .flags attribute list into the vartype enum.
+ */
+enum env_flags_vartype env_flags_parse_vartype(const char *flags)
+{
+	char *type;
+
+	if (strlen(flags) <= ENV_FLAGS_VARTYPE_LOC)
+		return env_flags_vartype_string;
+
+	type = strchr(env_flags_vartype_rep,
+		flags[ENV_FLAGS_VARTYPE_LOC]);
+
+	if (type != NULL)
+		return (enum env_flags_vartype)
+			(type - &env_flags_vartype_rep[0]);
+
+	printf("## Warning: Unknown environment variable type '%c'\n",
+		flags[ENV_FLAGS_VARTYPE_LOC]);
+	return env_flags_vartype_string;
+}
+
+static inline int is_hex_prefix(const char *value)
+{
+	return value[0] == '0' && (value[1] == 'x' || value[1] == 'X');
+}
+
+static void skip_num(int hex, const char *value, const char **end,
+	int max_digits)
+{
+	int i;
+
+	if (hex && is_hex_prefix(value))
+		value += 2;
+
+	for (i = max_digits; i != 0; i--) {
+		if (hex && !isxdigit(*value))
+			break;
+		if (!hex && !isdigit(*value))
+			break;
+		value++;
+	}
+	if (end != NULL)
+		*end = value;
+}
+
+/*
+ * Based on the declared type enum, validate that the value string complies
+ * with that format
+ */
+static int _env_flags_validate_type(const char *value,
+	enum env_flags_vartype type)
+{
+	const char *end;
+#ifdef CONFIG_CMD_NET
+	const char *cur;
+	int i;
+#endif
+
+	switch (type) {
+	case env_flags_vartype_string:
+		break;
+	case env_flags_vartype_decimal:
+		skip_num(0, value, &end, -1);
+		if (*end != '\0')
+			return -1;
+		break;
+	case env_flags_vartype_hex:
+		skip_num(1, value, &end, -1);
+		if (*end != '\0')
+			return -1;
+		if (value + 2 == end && is_hex_prefix(value))
+			return -1;
+		break;
+	case env_flags_vartype_bool:
+		if (value[0] != '1' && value[0] != 'y' && value[0] != 't' &&
+		    value[0] != 'Y' && value[0] != 'T' &&
+		    value[0] != '0' && value[0] != 'n' && value[0] != 'f' &&
+		    value[0] != 'N' && value[0] != 'F')
+			return -1;
+		if (value[1] != '\0')
+			return -1;
+		break;
+#ifdef CONFIG_CMD_NET
+	case env_flags_vartype_ipaddr:
+		cur = value;
+		for (i = 0; i < 4; i++) {
+			skip_num(0, cur, &end, 3);
+			if (cur == end)
+				return -1;
+			if (i != 3 && *end != '.')
+				return -1;
+			if (i == 3 && *end != '\0')
+				return -1;
+			cur = end + 1;
+		}
+		break;
+	case env_flags_vartype_macaddr:
+		cur = value;
+		for (i = 0; i < 6; i++) {
+			skip_num(1, cur, &end, 2);
+			if (cur == end)
+				return -1;
+			if (cur + 2 == end && is_hex_prefix(cur))
+				return -1;
+			if (i != 5 && *end != ':')
+				return -1;
+			if (i == 5 && *end != '\0')
+				return -1;
+			cur = end + 1;
+		}
+		break;
+#endif
+	case env_flags_vartype_end:
+		return -1;
+	}
+
+	/* OK */
+	return 0;
+}
+
+/*
+ * Look for flags in a provided list and failing that the static list
+ */
+static inline int env_flags_lookup(const char *flags_list, const char *name,
+	char *flags)
+{
+	int ret = 1;
+
+	if (!flags)
+		/* bad parameter */
+		return -1;
+
+	/* try the env first */
+	if (flags_list)
+		ret = env_attr_lookup(flags_list, name, flags);
+
+	if (ret != 0)
+		/* if not found in the env, look in the static list */
+		ret = env_attr_lookup(ENV_FLAGS_LIST_STATIC, name, flags);
+
+	return ret;
+}
+
+/*
+ * Parse the flag charachters from the .flags attribute list into the binary
+ * form to be stored in the environment entry->flags field.
+ */
+static int env_parse_flags_to_bin(const char *flags)
+{
+	return env_flags_parse_vartype(flags) & ENV_FLAGS_VARTYPE_BIN_MASK;
+}
+
+/*
+ * Look for possible flags for a newly added variable
+ * This is called specifically when the variable did not exist in the hash
+ * previously, so the blanket update did not find this variable.
+ */
+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;
+
+	/* look in the ".flags" and static for a reference to this variable */
+	ret = env_flags_lookup(flags_list, var_name, flags);
+
+	/* if any flags were found, set the binary form to the entry */
+	if (!ret && strlen(flags))
+		var_entry->flags = env_parse_flags_to_bin(flags);
+}
+
+/*
+ * Called on each existing env var prior to the blanket update since removing
+ * a flag in the flag list should remove its flags.
+ */
+static int clear_flags(ENTRY *entry)
+{
+	entry->flags = 0;
+
+	return 0;
+}
+
+/*
+ * Call for each element in the list that defines flags for a variable
+ */
+static int set_flags(const char *name, const char *value)
+{
+	ENTRY e, *ep;
+
+	e.key	= name;
+	e.data	= NULL;
+	hsearch_r(e, FIND, &ep, &env_htab, 0);
+
+	/* does the env variable actually exist? */
+	if (ep != NULL) {
+		/* the flag list is empty, so clear the flags */
+		if (value == NULL || strlen(value) == 0)
+			ep->flags = 0;
+		else
+			/* assign the requested flags */
+			ep->flags = env_parse_flags_to_bin(value);
+	}
+
+	return 0;
+}
+
+static int on_flags(const char *name, const char *value, enum env_op op,
+	int flags)
+{
+	/* remove all flags */
+	hwalk_r(&env_htab, clear_flags);
+
+	/* configure any static flags */
+	env_attr_walk(ENV_FLAGS_LIST_STATIC, set_flags);
+	/* configure any dynamic flags */
+	env_attr_walk(value, set_flags);
+
+	return 0;
+}
+U_BOOT_ENV_CALLBACK(flags, on_flags);
+
+/*
+ * Perform consistency checking before creating, overwriting, or deleting an
+ * environment variable. Called as a callback function by hsearch_r() and
+ * hdelete_r(). Returns 0 in case of success, 1 in case of failure.
+ * When (flag & H_FORCE) is set, do not print out any error message and force
+ * overwriting of write-once variables.
+ */
+
+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)
+			(ENV_FLAGS_VARTYPE_BIN_MASK & item->flags);
+
+		if (_env_flags_validate_type(newval, type) < 0) {
+			printf("## Error: flags type check failure for "
+				"\"%s\" <= \"%s\" (type: %c)\n",
+				name, newval, env_flags_vartype_rep[type]);
+			return -1;
+		}
+	}
+
+	return 0;
+}
diff --git a/include/env_callback.h b/include/env_callback.h
index f52e133..47fdc6f 100644
--- a/include/env_callback.h
+++ b/include/env_callback.h
@@ -24,6 +24,7 @@
 #ifndef __ENV_CALLBACK_H__
 #define __ENV_CALLBACK_H__
 
+#include <env_flags.h>
 #include <linker_lists.h>
 #include <search.h>
 
@@ -45,6 +46,7 @@
  * a new association in the ".callbacks" environment variable.
  */
 #define ENV_CALLBACK_LIST_STATIC ENV_CALLBACK_VAR ":callbacks," \
+	ENV_FLAGS_VAR ":flags," \
 	"baudrate:baudrate," \
 	"bootfile:bootfile," \
 	"loadaddr:loadaddr," \
diff --git a/include/env_default.h b/include/env_default.h
index d05eba1..39c5b7c 100644
--- a/include/env_default.h
+++ b/include/env_default.h
@@ -41,6 +41,9 @@ const uchar default_environment[] = {
 #ifdef	CONFIG_ENV_CALLBACK_LIST_DEFAULT
 	ENV_CALLBACK_VAR "=" CONFIG_ENV_CALLBACK_LIST_DEFAULT "\0"
 #endif
+#ifdef	CONFIG_ENV_FLAGS_LIST_DEFAULT
+	ENV_FLAGS_VAR "=" CONFIG_ENV_FLAGS_LIST_DEFAULT "\0"
+#endif
 #ifdef	CONFIG_BOOTARGS
 	"bootargs="	CONFIG_BOOTARGS			"\0"
 #endif
diff --git a/include/env_flags.h b/include/env_flags.h
new file mode 100644
index 0000000..bf25f27
--- /dev/null
+++ b/include/env_flags.h
@@ -0,0 +1,76 @@
+/*
+ * (C) Copyright 2012
+ * Joe Hershberger, National Instruments, joe.hershberger at 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
+ */
+
+#ifndef __ENV_FLAGS_H__
+#define __ENV_FLAGS_H__
+
+enum env_flags_vartype {
+	env_flags_vartype_string,
+	env_flags_vartype_decimal,
+	env_flags_vartype_hex,
+	env_flags_vartype_bool,
+#ifdef CONFIG_CMD_NET
+	env_flags_vartype_ipaddr,
+	env_flags_vartype_macaddr,
+#endif
+	env_flags_vartype_end
+};
+
+#define ENV_FLAGS_VAR ".flags"
+#define ENV_FLAGS_ATTR_MAX_LEN 2
+#define ENV_FLAGS_VARTYPE_LOC 0
+
+#ifndef CONFIG_ENV_FLAGS_LIST_STATIC
+#define CONFIG_ENV_FLAGS_LIST_STATIC ""
+#endif
+
+#define ENV_FLAGS_LIST_STATIC \
+	CONFIG_ENV_FLAGS_LIST_STATIC
+
+/*
+ * Parse the flags string from a .flags attribute list into the vartype enum.
+ */
+enum env_flags_vartype env_flags_parse_vartype(const char *flags);
+
+#include <search.h>
+
+/*
+ * When adding a variable to the environment, initialize the flags for that
+ * variable.
+ */
+void env_flags_init(ENTRY *var_entry);
+
+/*
+ * Validate the newval for to conform with the requirements defined by its flags
+ */
+int env_flags_validate(const ENTRY *item, const char *newval, enum env_op op,
+	int flag);
+
+/*
+ * These are the binary flags used in the environment entry->flags variable to
+ * decribe properties of veriables in the table
+ */
+#define ENV_FLAGS_VARTYPE_BIN_MASK	0x00000007
+/* The actual variable type values use the enum value (within the mask) */
+
+#endif /* __ENV_FLAGS_H__ */
diff --git a/include/environment.h b/include/environment.h
index 6c30215..00e59ba 100644
--- a/include/environment.h
+++ b/include/environment.h
@@ -166,6 +166,7 @@ extern void env_reloc(void);
 
 #include <env_attr.h>
 #include <env_callback.h>
+#include <env_flags.h>
 #include <search.h>
 
 extern struct hsearch_data env_htab;
@@ -189,14 +190,6 @@ int set_default_vars(int nvars, char * const vars[]);
 /* Import from binary representation into hash table */
 int env_import(const char *buf, int check);
 
-/*
- * Check if variable "item" can be changed to newval
- * When (flag & H_FORCE) is set, it does not print out any error
- * message and forces overwriting of write-once variables.
- */
-int env_change_ok(const ENTRY *item, const char *newval, enum env_op op,
-	int flag);
-
 #endif /* DO_DEPS_ONLY */
 
 #endif /* _ENVIRONMENT_H_ */
diff --git a/include/search.h b/include/search.h
index d68e24a..13d3be6 100644
--- a/include/search.h
+++ b/include/search.h
@@ -49,6 +49,7 @@ typedef struct entry {
 	char *data;
 	int (*callback)(const char *name, const char *value, enum env_op op,
 		int flags);
+	int flags;
 } ENTRY;
 
 /* Opaque type for internal use.  */
diff --git a/lib/hashtable.c b/lib/hashtable.c
index e922666..07ebfb2 100644
--- a/lib/hashtable.c
+++ b/lib/hashtable.c
@@ -55,6 +55,7 @@
 #endif
 
 #include <env_callback.h>
+#include <env_flags.h>
 #include <search.h>
 
 /*
@@ -412,6 +413,8 @@ int hsearch_r(ENTRY item, ACTION action, ENTRY ** retval,
 
 		/* This is a new entry, so look up a possible callback */
 		env_callback_init(&htab->table[idx].entry);
+		/* Also look for flags */
+		env_flags_init(&htab->table[idx].entry);
 
 		/* check for permission */
 		if (htab->change_ok != NULL && htab->change_ok(
@@ -465,6 +468,7 @@ static void _hdelete(const char *key, struct hsearch_data *htab, ENTRY *ep,
 	free((void *)ep->key);
 	free(ep->data);
 	ep->callback = NULL;
+	ep->flags = 0;
 	htab->table[idx].used = -1;
 
 	--htab->filled;
-- 
1.7.11.5

^ permalink raw reply related	[flat|nested] 124+ messages in thread

* [U-Boot] [PATCH v5 15/20] tools/env: Add environment variable flags support
  2012-12-12  4:16                                           ` [U-Boot] [PATCH v5 " Joe Hershberger
                                                               ` (13 preceding siblings ...)
  2012-12-12  4:16                                             ` [U-Boot] [PATCH v5 14/20] env: Add environment variable flags Joe Hershberger
@ 2012-12-12  4:16                                             ` Joe Hershberger
  2012-12-12  4:16                                             ` [U-Boot] [PATCH v5 16/20] env: Add a command to display details about env flags Joe Hershberger
                                                               ` (5 subsequent siblings)
  20 siblings, 0 replies; 124+ messages in thread
From: Joe Hershberger @ 2012-12-12  4:16 UTC (permalink / raw)
  To: u-boot

Currently just validates variable types as decimal, hexidecimal,
boolean, ip address, and mac address.  Call
env_acl_validate_setenv_params() from setenv() in fw_env.c.

If the entry is not found in the env .flags, then look in the static
one. This allows the env to override the static definitions, but prevents
the need to have every definition in the environment distracting you.

Need to build in _ctype for isdigit for Linux.

Signed-off-by: Joe Hershberger <joe.hershberger@ni.com>
---
Changes in v5: None
Changes in v4: None
Changes in v3: None
Changes in v2: None

 common/env_attr.c   |  7 +++++
 common/env_flags.c  | 75 +++++++++++++++++++++++++++++++++++++++++++++++++++++
 include/env_flags.h | 19 ++++++++++++++
 tools/env/Makefile  |  3 +++
 tools/env/fw_env.c  |  9 +++++++
 5 files changed, 113 insertions(+)

diff --git a/common/env_attr.c b/common/env_attr.c
index 7d330a5..210c98d 100644
--- a/common/env_attr.c
+++ b/common/env_attr.c
@@ -21,7 +21,14 @@
  * MA 02111-1307 USA
  */
 
+#ifdef USE_HOSTCC /* Eliminate "ANSI does not permit..." warnings */
+#include <stdint.h>
+#include <stdio.h>
+#include <linux/linux_string.h>
+#else
 #include <common.h>
+#endif
+
 #include <env_attr.h>
 #include <errno.h>
 #include <linux/string.h>
diff --git a/common/env_flags.c b/common/env_flags.c
index a58d614..ed0857c 100644
--- a/common/env_flags.c
+++ b/common/env_flags.c
@@ -24,8 +24,17 @@
 #include <linux/string.h>
 #include <linux/ctype.h>
 
+#ifdef USE_HOSTCC /* Eliminate "ANSI does not permit..." warnings */
+#include <stdint.h>
+#include <stdio.h>
+#include "fw_env.h"
+#include <env_attr.h>
+#include <env_flags.h>
+#define getenv fw_getenv
+#else
 #include <common.h>
 #include <environment.h>
+#endif
 
 #ifdef CONFIG_CMD_NET
 #define ENV_FLAGS_NET_VARTYPE_REPS "im"
@@ -179,6 +188,70 @@ static inline int env_flags_lookup(const char *flags_list, const char *name,
 	return ret;
 }
 
+#ifdef USE_HOSTCC /* Functions only used from tools/env */
+/*
+ * Look up any flags directly from the .flags variable and the static list
+ * and convert them to the vartype enum.
+ */
+enum env_flags_vartype env_flags_get_type(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_vartype_string;
+
+	if (strlen(flags) <= ENV_FLAGS_VARTYPE_LOC)
+		return env_flags_vartype_string;
+
+	return env_flags_parse_vartype(flags);
+}
+
+/*
+ * Validate that the proposed new value for "name" is valid according to the
+ * defined flags for that variable, if any.
+ */
+int env_flags_validate_type(const char *name, const char *value)
+{
+	enum env_flags_vartype type;
+
+	if (value == NULL)
+		return 0;
+	type = env_flags_get_type(name);
+	if (_env_flags_validate_type(value, type) < 0) {
+		printf("## Error: flags type check failure for "
+			"\"%s\" <= \"%s\" (type: %c)\n",
+			name, value, env_flags_vartype_rep[type]);
+		return -1;
+	}
+	return 0;
+}
+
+/*
+ * Validate the parameters to "env set" directly
+ */
+int env_flags_validate_env_set_params(int argc, char * const argv[])
+{
+	if ((argc >= 3) && argv[2] != NULL) {
+		enum env_flags_vartype type = env_flags_get_type(argv[1]);
+
+		/*
+		 * we don't currently check types that need more than
+		 * one argument
+		 */
+		if (type != env_flags_vartype_string && argc > 3) {
+			printf("## Error: too many parameters for setting "
+				"\"%s\"\n", argv[1]);
+			return -1;
+		}
+		return env_flags_validate_type(argv[1], argv[2]);
+	}
+	/* ok */
+	return 0;
+}
+
+#else /* !USE_HOSTCC - Functions only used from lib/hashtable.c */
+
 /*
  * Parse the flag charachters from the .flags attribute list into the binary
  * form to be stored in the environment entry->flags field.
@@ -317,3 +390,5 @@ int env_flags_validate(const ENTRY *item, const char *newval, enum env_op op,
 
 	return 0;
 }
+
+#endif
diff --git a/include/env_flags.h b/include/env_flags.h
index bf25f27..3333446 100644
--- a/include/env_flags.h
+++ b/include/env_flags.h
@@ -52,6 +52,23 @@ enum env_flags_vartype {
  */
 enum env_flags_vartype env_flags_parse_vartype(const char *flags);
 
+#ifdef USE_HOSTCC
+/*
+ * Look up the type of a variable directly from the .flags var.
+ */
+enum env_flags_vartype env_flags_get_type(const char *name);
+/*
+ * Validate the newval for its type to conform with the requirements defined by
+ * its flags (directly looked at the .flags var).
+ */
+int env_flags_validate_type(const char *name, const char *newval);
+/*
+ * Validate the parameters passed to "env set" for type compliance
+ */
+int env_flags_validate_env_set_params(int argc, char * const argv[]);
+
+#else /* !USE_HOSTCC */
+
 #include <search.h>
 
 /*
@@ -73,4 +90,6 @@ int env_flags_validate(const ENTRY *item, const char *newval, enum env_op op,
 #define ENV_FLAGS_VARTYPE_BIN_MASK	0x00000007
 /* The actual variable type values use the enum value (within the mask) */
 
+#endif /* USE_HOSTCC */
+
 #endif /* __ENV_FLAGS_H__ */
diff --git a/tools/env/Makefile b/tools/env/Makefile
index ab73c8c..0e798e0 100644
--- a/tools/env/Makefile
+++ b/tools/env/Makefile
@@ -24,12 +24,15 @@
 include $(TOPDIR)/config.mk
 
 HOSTSRCS := $(SRCTREE)/lib/crc32.c  fw_env.c  fw_env_main.c
+HOSTSRCS += $(SRCTREE)/lib/ctype.c $(SRCTREE)/lib/linux_string.c
+HOSTSRCS += $(SRCTREE)/common/env_attr.c $(SRCTREE)/common/env_flags.c
 HEADERS	:= fw_env.h $(OBJTREE)/include/config.h
 
 # Compile for a hosted environment on the target
 HOSTCPPFLAGS  = -idirafter $(SRCTREE)/include \
 		-idirafter $(OBJTREE)/include2 \
 		-idirafter $(OBJTREE)/include \
+		-idirafter $(SRCTREE)/tools/env \
 		-DUSE_HOSTCC \
 		-DTEXT_BASE=$(TEXT_BASE)
 
diff --git a/tools/env/fw_env.c b/tools/env/fw_env.c
index 9b023e8..5be36fc 100644
--- a/tools/env/fw_env.c
+++ b/tools/env/fw_env.c
@@ -25,6 +25,7 @@
  */
 
 #include <errno.h>
+#include <env_flags.h>
 #include <fcntl.h>
 #include <linux/stringify.h>
 #include <stdio.h>
@@ -395,6 +396,9 @@ int fw_setenv(int argc, char *argv[])
 
 	name = argv[1];
 
+	if (env_flags_validate_env_set_params(argc, argv) < 0)
+		return 1;
+
 	len = 0;
 	for (i = 2; i < argc; ++i) {
 		char *val = argv[i];
@@ -516,6 +520,11 @@ int fw_parse_script(char *fname)
 			name, val ? val : " removed");
 #endif
 
+		if (env_flags_validate_type(name, val) < 0) {
+			ret = -1;
+			break;
+		}
+
 		/*
 		 * If there is an error setting a variable,
 		 * try to save the environment and returns an error
-- 
1.7.11.5

^ permalink raw reply related	[flat|nested] 124+ messages in thread

* [U-Boot] [PATCH v5 16/20] env: Add a command to display details about env flags
  2012-12-12  4:16                                           ` [U-Boot] [PATCH v5 " Joe Hershberger
                                                               ` (14 preceding siblings ...)
  2012-12-12  4:16                                             ` [U-Boot] [PATCH v5 15/20] tools/env: Add environment variable flags support Joe Hershberger
@ 2012-12-12  4:16                                             ` Joe Hershberger
  2012-12-12  4:16                                             ` [U-Boot] [PATCH v5 17/20] env: Add support for access control to .flags Joe Hershberger
                                                               ` (4 subsequent siblings)
  20 siblings, 0 replies; 124+ messages in thread
From: Joe Hershberger @ 2012-12-12  4:16 UTC (permalink / raw)
  To: u-boot

Similar to the env callback command, this will show details about the
options available, the static list, and the currently active variables.

Signed-off-by: Joe Hershberger <joe.hershberger@ni.com>
---
Changes in v5: None
Changes in v4:
- Add help text for env flags command

Changes in v3: None
Changes in v2: None

 README              |  1 +
 common/cmd_nvedit.c | 59 +++++++++++++++++++++++++++++++++++++++++++++++++++++
 common/env_flags.c  | 34 ++++++++++++++++++++++++++++++
 include/env_flags.h | 11 ++++++++++
 4 files changed, 105 insertions(+)

diff --git a/README b/README
index 5705925..efce998 100644
--- a/README
+++ b/README
@@ -811,6 +811,7 @@ The following options need to be configured:
 		CONFIG_CMD_EEPROM	* EEPROM read/write support
 		CONFIG_CMD_ELF		* bootelf, bootvx
 		CONFIG_CMD_ENV_CALLBACK	* display details about env callbacks
+		CONFIG_CMD_ENV_FLAGS	* display details about env flags
 		CONFIG_CMD_EXPORTENV	* export the environment
 		CONFIG_CMD_EXT2		* ext2 command support
 		CONFIG_CMD_EXT4		* ext4 command support
diff --git a/common/cmd_nvedit.c b/common/cmd_nvedit.c
index f645194..468b89c 100644
--- a/common/cmd_nvedit.c
+++ b/common/cmd_nvedit.c
@@ -443,6 +443,59 @@ int do_env_callback(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
 }
 #endif
 
+#if defined(CONFIG_CMD_ENV_FLAGS)
+static int print_static_flags(const char *var_name, const char *flags)
+{
+	enum env_flags_vartype type = env_flags_parse_vartype(flags);
+
+	printf("\t%-20s %-20s\n", var_name, env_flags_get_vartype_name(type));
+
+	return 0;
+}
+
+static int print_active_flags(ENTRY *entry)
+{
+	enum env_flags_vartype type;
+
+	if (entry->flags == 0)
+		return 0;
+
+	type = (enum env_flags_vartype)
+		(entry->flags & ENV_FLAGS_VARTYPE_BIN_MASK);
+	printf("\t%-20s %-20s\n", entry->key, env_flags_get_vartype_name(type));
+
+	return 0;
+}
+
+/*
+ * Print the flags available and what variables have flags
+ */
+int do_env_flags(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
+{
+	/* Print the available variable types */
+	printf("Available variable type flags (position %d):\n",
+		ENV_FLAGS_VARTYPE_LOC);
+	puts("\tFlag\tVariable Type Name\n");
+	puts("\t----\t------------------\n");
+	env_flags_print_vartypes();
+	puts("\n");
+
+	/* Print the static flags that may exist */
+	puts("Static flags:\n");
+	printf("\t%-20s %-20s\n", "Variable Name", "Variable Type");
+	printf("\t%-20s %-20s\n", "-------------", "-------------");
+	env_attr_walk(ENV_FLAGS_LIST_STATIC, print_static_flags);
+	puts("\n");
+
+	/* walk through each variable and print the flags if non-default */
+	puts("Active flags:\n");
+	printf("\t%-20s %-20s\n", "Variable Name", "Variable Type");
+	printf("\t%-20s %-20s\n", "-------------", "-------------");
+	hwalk_r(&env_htab, print_active_flags);
+	return 0;
+}
+#endif
+
 /*
  * Interactively edit an environment variable
  */
@@ -913,6 +966,9 @@ static cmd_tbl_t cmd_env_sub[] = {
 #if defined(CONFIG_CMD_ENV_CALLBACK)
 	U_BOOT_CMD_MKENT(callbacks, 1, 0, do_env_callback, "", ""),
 #endif
+#if defined(CONFIG_CMD_ENV_FLAGS)
+	U_BOOT_CMD_MKENT(flags, 1, 0, do_env_flags, "", ""),
+#endif
 #if defined(CONFIG_CMD_EXPORTENV)
 	U_BOOT_CMD_MKENT(export, 4, 0, do_env_export, "", ""),
 #endif
@@ -974,6 +1030,9 @@ static char env_help_text[] =
 #if defined(CONFIG_CMD_EXPORTENV)
 	"env export [-t | -b | -c] [-s size] addr [var ...] - export environment\n"
 #endif
+#if defined(CONFIG_CMD_ENV_FLAGS)
+	"env flags - print variables that have non-default flags\n"
+#endif
 #if defined(CONFIG_CMD_GREPENV)
 	"env grep string [...] - search environment\n"
 #endif
diff --git a/common/env_flags.c b/common/env_flags.c
index ed0857c..09f93d5 100644
--- a/common/env_flags.c
+++ b/common/env_flags.c
@@ -43,6 +43,40 @@
 #endif
 
 static const char env_flags_vartype_rep[] = "sdxb" ENV_FLAGS_NET_VARTYPE_REPS;
+#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
+};
+
+/*
+ * 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++;
+	}
+}
+
+/*
+ * Return the name of the type.
+ */
+const char *env_flags_get_vartype_name(enum env_flags_vartype type)
+{
+	return env_flags_vartype_names[type];
+}
+#endif /* CONFIG_CMD_ENV_FLAGS */
 
 /*
  * Parse the flags string from a .flags attribute list into the vartype enum.
diff --git a/include/env_flags.h b/include/env_flags.h
index 3333446..7e72523 100644
--- a/include/env_flags.h
+++ b/include/env_flags.h
@@ -47,6 +47,17 @@ enum env_flags_vartype {
 #define ENV_FLAGS_LIST_STATIC \
 	CONFIG_ENV_FLAGS_LIST_STATIC
 
+#ifdef CONFIG_CMD_ENV_FLAGS
+/*
+ * Print the whole list of available type flags.
+ */
+void env_flags_print_vartypes(void);
+/*
+ * Return the name of the type.
+ */
+const char *env_flags_get_vartype_name(enum env_flags_vartype type);
+#endif
+
 /*
  * Parse the flags string from a .flags attribute list into the vartype enum.
  */
-- 
1.7.11.5

^ permalink raw reply related	[flat|nested] 124+ messages in thread

* [U-Boot] [PATCH v5 17/20] env: Add support for access control to .flags
  2012-12-12  4:16                                           ` [U-Boot] [PATCH v5 " Joe Hershberger
                                                               ` (15 preceding siblings ...)
  2012-12-12  4:16                                             ` [U-Boot] [PATCH v5 16/20] env: Add a command to display details about env flags Joe Hershberger
@ 2012-12-12  4:16                                             ` Joe Hershberger
  2012-12-12  4:16                                             ` [U-Boot] [PATCH v5 18/20] env: Add setenv force support Joe Hershberger
                                                               ` (3 subsequent siblings)
  20 siblings, 0 replies; 124+ messages in thread
From: Joe Hershberger @ 2012-12-12  4:16 UTC (permalink / raw)
  To: u-boot

Add support for read-only, write-once, and change-default.

Signed-off-by: Joe Hershberger <joe.hershberger@ni.com>
---
Changes in v5:
- Fixed out-of-bounds array access in env_flags_parse_varaccess()

Changes in v4: None
Changes in v3: None
Changes in v2: None

 README                |  13 ++++-
 common/cmd_nvedit.c   |  31 ++++++++--
 common/env_common.c   |  18 ++++++
 common/env_flags.c    | 159 ++++++++++++++++++++++++++++++++++++++++++++++++--
 include/env_flags.h   |  50 +++++++++++++++-
 include/environment.h |   3 +
 tools/env/fw_env.c    |  74 +++++++++++++++++++++--
 7 files changed, 330 insertions(+), 18 deletions(-)

diff --git a/README b/README
index efce998..28abf89 100644
--- a/README
+++ b/README
@@ -3083,7 +3083,8 @@ Configuration Settings:
 
 	The format of the list is:
 		type_attribute = [s|d|x|b|i|m]
-		attributes = type_attribute
+		access_atribute = [a|r|o|c]
+		attributes = type_attribute[access_atribute]
 		entry = variable_name[:attributes]
 		list = entry[,list]
 
@@ -3095,6 +3096,12 @@ Configuration Settings:
 		i - IP address
 		m - MAC address
 
+	The access attributes are:
+		a - Any (default)
+		r - Read-only
+		o - Write-once
+		c - Change-default
+
 	- CONFIG_ENV_FLAGS_LIST_DEFAULT
 		Define this to a list (string) to define the ".flags"
 		envirnoment variable in the default or embedded environment.
@@ -3106,6 +3113,10 @@ Configuration Settings:
 		list, simply add an entry for the same variable name to the
 		".flags" variable.
 
+- CONFIG_ENV_ACCESS_IGNORE_FORCE
+	If defined, don't allow the -f switch to env set override variable
+	access flags.
+
 The following definitions that deal with the placement and management
 of environment data (variable area); in general, we support the
 following configurations:
diff --git a/common/cmd_nvedit.c b/common/cmd_nvedit.c
index 468b89c..e8dfbf5 100644
--- a/common/cmd_nvedit.c
+++ b/common/cmd_nvedit.c
@@ -447,8 +447,11 @@ int do_env_callback(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
 static int print_static_flags(const char *var_name, const char *flags)
 {
 	enum env_flags_vartype type = env_flags_parse_vartype(flags);
+	enum env_flags_varaccess access = env_flags_parse_varaccess(flags);
 
-	printf("\t%-20s %-20s\n", var_name, env_flags_get_vartype_name(type));
+	printf("\t%-20s %-20s %-20s\n", var_name,
+		env_flags_get_vartype_name(type),
+		env_flags_get_varaccess_name(access));
 
 	return 0;
 }
@@ -456,13 +459,17 @@ static int print_static_flags(const char *var_name, const char *flags)
 static int print_active_flags(ENTRY *entry)
 {
 	enum env_flags_vartype type;
+	enum env_flags_varaccess access;
 
 	if (entry->flags == 0)
 		return 0;
 
 	type = (enum env_flags_vartype)
 		(entry->flags & ENV_FLAGS_VARTYPE_BIN_MASK);
-	printf("\t%-20s %-20s\n", entry->key, env_flags_get_vartype_name(type));
+	access = env_flags_parse_varaccess_from_binflags(entry->flags);
+	printf("\t%-20s %-20s %-20s\n", entry->key,
+		env_flags_get_vartype_name(type),
+		env_flags_get_varaccess_name(access));
 
 	return 0;
 }
@@ -480,17 +487,29 @@ int do_env_flags(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
 	env_flags_print_vartypes();
 	puts("\n");
 
+	/* Print the available variable access types */
+	printf("Available variable access flags (position %d):\n",
+		ENV_FLAGS_VARACCESS_LOC);
+	puts("\tFlag\tVariable Access Name\n");
+	puts("\t----\t--------------------\n");
+	env_flags_print_varaccess();
+	puts("\n");
+
 	/* Print the static flags that may exist */
 	puts("Static flags:\n");
-	printf("\t%-20s %-20s\n", "Variable Name", "Variable Type");
-	printf("\t%-20s %-20s\n", "-------------", "-------------");
+	printf("\t%-20s %-20s %-20s\n", "Variable Name", "Variable Type",
+		"Variable Access");
+	printf("\t%-20s %-20s %-20s\n", "-------------", "-------------",
+		"---------------");
 	env_attr_walk(ENV_FLAGS_LIST_STATIC, print_static_flags);
 	puts("\n");
 
 	/* walk through each variable and print the flags if non-default */
 	puts("Active flags:\n");
-	printf("\t%-20s %-20s\n", "Variable Name", "Variable Type");
-	printf("\t%-20s %-20s\n", "-------------", "-------------");
+	printf("\t%-20s %-20s %-20s\n", "Variable Name", "Variable Type",
+		"Variable Access");
+	printf("\t%-20s %-20s %-20s\n", "-------------", "-------------",
+		"---------------");
 	hwalk_r(&env_htab, print_active_flags);
 	return 0;
 }
diff --git a/common/env_common.c b/common/env_common.c
index bb18070..906b41f 100644
--- a/common/env_common.c
+++ b/common/env_common.c
@@ -95,6 +95,24 @@ int getenv_yesno(const char *var)
 		1 : 0;
 }
 
+/*
+ * Look up the variable from the default environment
+ */
+char *getenv_default(const char *name)
+{
+	char *ret_val;
+	unsigned long really_valid = gd->env_valid;
+	unsigned long real_gd_flags = gd->flags;
+
+	/* Pretend that the image is bad. */
+	gd->flags &= ~GD_FLG_ENV_READY;
+	gd->env_valid = 0;
+	ret_val = getenv(name);
+	gd->env_valid = really_valid;
+	gd->flags = real_gd_flags;
+	return ret_val;
+}
+
 void set_default_env(const char *s)
 {
 	int flags = 0;
diff --git a/common/env_flags.c b/common/env_flags.c
index 09f93d5..4caf12e 100644
--- a/common/env_flags.c
+++ b/common/env_flags.c
@@ -43,6 +43,17 @@
 #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",
@@ -54,6 +65,12 @@ static const char * const env_flags_vartype_names[] = {
 	"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.
@@ -70,12 +87,34 @@ void env_flags_print_vartypes(void)
 }
 
 /*
+ * 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 */
 
 /*
@@ -100,6 +139,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');
@@ -242,6 +321,23 @@ enum env_flags_vartype env_flags_get_type(const char *name)
 }
 
 /*
+ * 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.
  */
@@ -262,6 +358,21 @@ int env_flags_validate_type(const char *name, const char *value)
 }
 
 /*
+ * 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
  */
 int env_flags_validate_env_set_params(int argc, char * const argv[])
@@ -292,7 +403,12 @@ 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;
 }
 
 /*
@@ -377,13 +493,10 @@ 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;
 
@@ -422,6 +535,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;
 }
 
diff --git a/include/env_flags.h b/include/env_flags.h
index 7e72523..0bdae07 100644
--- a/include/env_flags.h
+++ b/include/env_flags.h
@@ -36,9 +36,18 @@ enum env_flags_vartype {
 	env_flags_vartype_end
 };
 
+enum env_flags_varaccess {
+	env_flags_varaccess_any,
+	env_flags_varaccess_readonly,
+	env_flags_varaccess_writeonce,
+	env_flags_varaccess_changedefault,
+	env_flags_varaccess_end
+};
+
 #define ENV_FLAGS_VAR ".flags"
 #define ENV_FLAGS_ATTR_MAX_LEN 2
 #define ENV_FLAGS_VARTYPE_LOC 0
+#define ENV_FLAGS_VARACCESS_LOC 1
 
 #ifndef CONFIG_ENV_FLAGS_LIST_STATIC
 #define CONFIG_ENV_FLAGS_LIST_STATIC ""
@@ -53,15 +62,31 @@ enum env_flags_vartype {
  */
 void env_flags_print_vartypes(void);
 /*
+ * Print the whole list of available access flags.
+ */
+void env_flags_print_varaccess(void);
+/*
  * Return the name of the type.
  */
 const char *env_flags_get_vartype_name(enum env_flags_vartype type);
+/*
+ * Return the name of the access.
+ */
+const char *env_flags_get_varaccess_name(enum env_flags_varaccess access);
 #endif
 
 /*
  * Parse the flags string from a .flags attribute list into the vartype enum.
  */
 enum env_flags_vartype env_flags_parse_vartype(const char *flags);
+/*
+ * Parse the flags string from a .flags attribute list into the varaccess enum.
+ */
+enum env_flags_varaccess env_flags_parse_varaccess(const char *flags);
+/*
+ * 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);
 
 #ifdef USE_HOSTCC
 /*
@@ -69,11 +94,25 @@ enum env_flags_vartype env_flags_parse_vartype(const char *flags);
  */
 enum env_flags_vartype env_flags_get_type(const char *name);
 /*
+ * Look up the access of a variable directly from the .flags var.
+ */
+enum env_flags_varaccess env_flags_get_access(const char *name);
+/*
  * Validate the newval for its type to conform with the requirements defined by
  * its flags (directly looked at the .flags var).
  */
 int env_flags_validate_type(const char *name, const char *newval);
 /*
+ * Validate the newval for its access to conform with the requirements defined
+ * by its flags (directly looked at the .flags var).
+ */
+int env_flags_validate_access(const char *name, int check_mask);
+/*
+ * 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);
+/*
  * Validate the parameters passed to "env set" for type compliance
  */
 int env_flags_validate_env_set_params(int argc, char * const argv[]);
@@ -94,13 +133,18 @@ void env_flags_init(ENTRY *var_entry);
 int env_flags_validate(const ENTRY *item, const char *newval, enum env_op op,
 	int flag);
 
+#endif /* USE_HOSTCC */
+
 /*
  * These are the binary flags used in the environment entry->flags variable to
  * decribe properties of veriables in the table
  */
-#define ENV_FLAGS_VARTYPE_BIN_MASK	0x00000007
+#define ENV_FLAGS_VARTYPE_BIN_MASK			0x00000007
 /* The actual variable type values use the enum value (within the mask) */
-
-#endif /* USE_HOSTCC */
+#define ENV_FLAGS_VARACCESS_PREVENT_DELETE		0x00000008
+#define ENV_FLAGS_VARACCESS_PREVENT_CREATE		0x00000010
+#define ENV_FLAGS_VARACCESS_PREVENT_OVERWR		0x00000020
+#define ENV_FLAGS_VARACCESS_PREVENT_NONDEF_OVERWR	0x00000040
+#define ENV_FLAGS_VARACCESS_BIN_MASK			0x00000078
 
 #endif /* __ENV_FLAGS_H__ */
diff --git a/include/environment.h b/include/environment.h
index 00e59ba..e64b43d 100644
--- a/include/environment.h
+++ b/include/environment.h
@@ -181,6 +181,9 @@ unsigned char env_get_char_memory(int index);
 /* Function that updates CRC of the enironment */
 void env_crc_update(void);
 
+/* Look up the variable from the default environment */
+char *getenv_default(const char *name);
+
 /* [re]set to the default environment */
 void set_default_env(const char *s);
 
diff --git a/tools/env/fw_env.c b/tools/env/fw_env.c
index 5be36fc..a596a1b 100644
--- a/tools/env/fw_env.c
+++ b/tools/env/fw_env.c
@@ -182,6 +182,32 @@ char *fw_getenv (char *name)
 }
 
 /*
+ * Search the default environment for a variable.
+ * Return the value, if found, or NULL, if not found.
+ */
+char *fw_getdefenv(char *name)
+{
+	char *env, *nxt;
+
+	for (env = default_environment; *env; env = nxt + 1) {
+		char *val;
+
+		for (nxt = env; *nxt; ++nxt) {
+			if (nxt >= &default_environment[ENV_SIZE]) {
+				fprintf(stderr, "## Error: "
+					"default environment not terminated\n");
+				return NULL;
+			}
+		}
+		val = envmatch(name, env);
+		if (!val)
+			continue;
+		return val;
+	}
+	return NULL;
+}
+
+/*
  * Print the current definition of one, or more, or all
  * environment variables
  */
@@ -282,6 +308,7 @@ int fw_env_write(char *name, char *value)
 	int len;
 	char *env, *nxt;
 	char *oldval = NULL;
+	int deleting, creating, overwriting;
 
 	/*
 	 * search if variable with this name already exists
@@ -299,10 +326,49 @@ int fw_env_write(char *name, char *value)
 			break;
 	}
 
-	/*
-	 * Delete any existing definition
-	 */
-	if (oldval) {
+	deleting = (oldval && !(value && strlen(value)));
+	creating = (!oldval && (value && strlen(value)));
+	overwriting = (oldval && (value && strlen(value)));
+
+	/* check for permission */
+	if (deleting) {
+		if (env_flags_validate_varaccess(name,
+		    ENV_FLAGS_VARACCESS_PREVENT_DELETE)) {
+			printf("Can't delete \"%s\"\n", name);
+			errno = EROFS;
+			return -1;
+		}
+	} else if (overwriting) {
+		if (env_flags_validate_varaccess(name,
+		    ENV_FLAGS_VARACCESS_PREVENT_OVERWR)) {
+			printf("Can't overwrite \"%s\"\n", name);
+			errno = EROFS;
+			return -1;
+		} else if (env_flags_validate_varaccess(name,
+		    ENV_FLAGS_VARACCESS_PREVENT_NONDEF_OVERWR)) {
+			const char *defval = fw_getdefenv(name);
+
+			if (defval == NULL)
+				defval = "";
+			if (strcmp(oldval, defval)
+			    != 0) {
+				printf("Can't overwrite \"%s\"\n", name);
+				errno = EROFS;
+				return -1;
+			}
+		}
+	} else if (creating) {
+		if (env_flags_validate_varaccess(name,
+		    ENV_FLAGS_VARACCESS_PREVENT_CREATE)) {
+			printf("Can't create \"%s\"\n", name);
+			errno = EROFS;
+			return -1;
+		}
+	} else
+		/* Nothing to do */
+		return 0;
+
+	if (deleting || overwriting) {
 #ifndef CONFIG_ENV_OVERWRITE
 		/*
 		 * Ethernet Address and serial# can be set only once
-- 
1.7.11.5

^ permalink raw reply related	[flat|nested] 124+ messages in thread

* [U-Boot] [PATCH v5 18/20] env: Add setenv force support
  2012-12-12  4:16                                           ` [U-Boot] [PATCH v5 " Joe Hershberger
                                                               ` (16 preceding siblings ...)
  2012-12-12  4:16                                             ` [U-Boot] [PATCH v5 17/20] env: Add support for access control to .flags Joe Hershberger
@ 2012-12-12  4:16                                             ` Joe Hershberger
  2012-12-12  4:16                                             ` [U-Boot] [PATCH v5 19/20] env: Implement the env delete command Joe Hershberger
                                                               ` (2 subsequent siblings)
  20 siblings, 0 replies; 124+ messages in thread
From: Joe Hershberger @ 2012-12-12  4:16 UTC (permalink / raw)
  To: u-boot

Now that we have support for permissions, add a way to override them.

Signed-off-by: Joe Hershberger <joe.hershberger@ni.com>
---
Changes in v5: None
Changes in v4:
- Add force support to setenv

Changes in v3: None
Changes in v2: None

 common/cmd_nvedit.c | 29 +++++++++++++++++++++++------
 1 file changed, 23 insertions(+), 6 deletions(-)

diff --git a/common/cmd_nvedit.c b/common/cmd_nvedit.c
index e8dfbf5..988d6b3 100644
--- a/common/cmd_nvedit.c
+++ b/common/cmd_nvedit.c
@@ -200,7 +200,24 @@ static int _do_env_set(int flag, int argc, char * const argv[])
 	int   i, len;
 	char  *name, *value, *s;
 	ENTRY e, *ep;
+	int env_flag = H_INTERACTIVE;
 
+	debug("Initial value for argc=%d\n", argc);
+	while (argc > 1 && **(argv + 1) == '-') {
+		char *arg = *++argv;
+
+		--argc;
+		while (*++arg) {
+			switch (*arg) {
+			case 'f':		/* force */
+				env_flag |= H_FORCE;
+				break;
+			default:
+				return CMD_RET_USAGE;
+			}
+		}
+	}
+	debug("Final value for argc=%d\n", argc);
 	name = argv[1];
 	value = argv[2];
 
@@ -214,7 +231,7 @@ static int _do_env_set(int flag, int argc, char * const argv[])
 
 	/* Delete only ? */
 	if (argc < 3 || argv[2] == NULL) {
-		int rc = hdelete_r(name, &env_htab, H_INTERACTIVE);
+		int rc = hdelete_r(name, &env_htab, env_flag);
 		return !rc;
 	}
 
@@ -241,7 +258,7 @@ static int _do_env_set(int flag, int argc, char * const argv[])
 
 	e.key	= name;
 	e.data	= value;
-	hsearch_r(e, ENTER, &ep, &env_htab, H_INTERACTIVE);
+	hsearch_r(e, ENTER, &ep, &env_htab, env_flag);
 	free(value);
 	if (!ep) {
 		printf("## Error inserting \"%s\" variable, errno=%d\n",
@@ -1109,10 +1126,10 @@ U_BOOT_CMD_COMPLETE(
 U_BOOT_CMD_COMPLETE(
 	setenv, CONFIG_SYS_MAXARGS, 0,	do_env_set,
 	"set environment variables",
-	"name value ...\n"
-	"    - set environment variable 'name' to 'value ...'\n"
-	"setenv name\n"
-	"    - delete environment variable 'name'",
+	"[-f] name value ...\n"
+	"    - [forcibly] set environment variable 'name' to 'value ...'\n"
+	"setenv [-f] name\n"
+	"    - [forcibly] delete environment variable 'name'",
 	var_complete
 );
 
-- 
1.7.11.5

^ permalink raw reply related	[flat|nested] 124+ messages in thread

* [U-Boot] [PATCH v5 19/20] env: Implement the env delete command
  2012-12-12  4:16                                           ` [U-Boot] [PATCH v5 " Joe Hershberger
                                                               ` (17 preceding siblings ...)
  2012-12-12  4:16                                             ` [U-Boot] [PATCH v5 18/20] env: Add setenv force support Joe Hershberger
@ 2012-12-12  4:16                                             ` Joe Hershberger
  2012-12-12  4:16                                             ` [U-Boot] [PATCH v5 20/20] env: Handle write-once ethaddr and serial# generically Joe Hershberger
  2012-12-14 16:05                                             ` [U-Boot] [PATCH v5 0/20] Add environment call-back and flags capability Tom Rini
  20 siblings, 0 replies; 124+ messages in thread
From: Joe Hershberger @ 2012-12-12  4:16 UTC (permalink / raw)
  To: u-boot

Implement a way to delete more than one variable at a time.

Signed-off-by: Joe Hershberger <joe.hershberger@ni.com>
---
Changes in v5: None
Changes in v4:
- Implement delete

Changes in v3: None
Changes in v2: None

 common/cmd_nvedit.c | 35 ++++++++++++++++++++++++++++++++---
 1 file changed, 32 insertions(+), 3 deletions(-)

diff --git a/common/cmd_nvedit.c b/common/cmd_nvedit.c
index 988d6b3..7633f0c 100644
--- a/common/cmd_nvedit.c
+++ b/common/cmd_nvedit.c
@@ -725,8 +725,36 @@ static int do_env_default(cmd_tbl_t *cmdtp, int __flag,
 static int do_env_delete(cmd_tbl_t *cmdtp, int flag,
 			 int argc, char * const argv[])
 {
-	printf("Not implemented yet\n");
-	return 0;
+	int env_flag = H_INTERACTIVE;
+	int ret = 0;
+
+	debug("Initial value for argc=%d\n", argc);
+	while (argc > 1 && **(argv + 1) == '-') {
+		char *arg = *++argv;
+
+		--argc;
+		while (*++arg) {
+			switch (*arg) {
+			case 'f':		/* force */
+				env_flag |= H_FORCE;
+				break;
+			default:
+				return CMD_RET_USAGE;
+			}
+		}
+	}
+	debug("Final value for argc=%d\n", argc);
+
+	env_id++;
+
+	while (--argc > 0) {
+		char *name = *++argv;
+
+		if (!hdelete_r(name, &env_htab, env_flag))
+			ret = 1;
+	}
+
+	return ret;
 }
 
 #ifdef CONFIG_CMD_EXPORTENV
@@ -995,7 +1023,7 @@ static cmd_tbl_t cmd_env_sub[] = {
 	U_BOOT_CMD_MKENT(ask, CONFIG_SYS_MAXARGS, 1, do_env_ask, "", ""),
 #endif
 	U_BOOT_CMD_MKENT(default, 1, 0, do_env_default, "", ""),
-	U_BOOT_CMD_MKENT(delete, 2, 0, do_env_delete, "", ""),
+	U_BOOT_CMD_MKENT(delete, CONFIG_SYS_MAXARGS, 0, do_env_delete, "", ""),
 #if defined(CONFIG_CMD_EDITENV)
 	U_BOOT_CMD_MKENT(edit, 2, 0, do_env_edit, "", ""),
 #endif
@@ -1060,6 +1088,7 @@ static char env_help_text[] =
 #endif
 	"default [-f] -a - [forcibly] reset default environment\n"
 	"env default [-f] var [...] - [forcibly] reset variable(s) to their default values\n"
+	"env delete [-f] var [...] - [forcibly] delete variable(s)\n"
 #if defined(CONFIG_CMD_EDITENV)
 	"env edit name - edit environment variable\n"
 #endif
-- 
1.7.11.5

^ permalink raw reply related	[flat|nested] 124+ messages in thread

* [U-Boot] [PATCH v5 20/20] env: Handle write-once ethaddr and serial# generically
  2012-12-12  4:16                                           ` [U-Boot] [PATCH v5 " Joe Hershberger
                                                               ` (18 preceding siblings ...)
  2012-12-12  4:16                                             ` [U-Boot] [PATCH v5 19/20] env: Implement the env delete command Joe Hershberger
@ 2012-12-12  4:16                                             ` Joe Hershberger
  2012-12-14 16:05                                             ` [U-Boot] [PATCH v5 0/20] Add environment call-back and flags capability Tom Rini
  20 siblings, 0 replies; 124+ messages in thread
From: Joe Hershberger @ 2012-12-12  4:16 UTC (permalink / raw)
  To: u-boot

Use the variable access flags to implement the protection for ethaddr
and serial# instead of hard-coding them.

Signed-off-by: Joe Hershberger <joe.hershberger@ni.com>
---
Changes in v5: None
Changes in v4: None
Changes in v3: None
Changes in v2: None

 common/env_flags.c  | 19 -------------------
 include/env_flags.h | 22 ++++++++++++++++++++++
 tools/env/fw_env.c  | 17 -----------------
 3 files changed, 22 insertions(+), 36 deletions(-)

diff --git a/common/env_flags.c b/common/env_flags.c
index 4caf12e..336cae4 100644
--- a/common/env_flags.c
+++ b/common/env_flags.c
@@ -503,25 +503,6 @@ int env_flags_validate(const ENTRY *item, const char *newval, enum env_op op,
 	/* 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)
diff --git a/include/env_flags.h b/include/env_flags.h
index 0bdae07..d1aa144 100644
--- a/include/env_flags.h
+++ b/include/env_flags.h
@@ -53,7 +53,29 @@ enum env_flags_varaccess {
 #define CONFIG_ENV_FLAGS_LIST_STATIC ""
 #endif
 
+#ifdef CONFIG_CMD_NET
+#ifdef CONFIG_ENV_OVERWRITE
+#define ETHADDR_FLAGS "ethaddr:ma,"
+#else
+#ifdef CONFIG_OVERWRITE_ETHADDR_ONCE
+#define ETHADDR_FLAGS "ethaddr:mc,"
+#else
+#define ETHADDR_FLAGS "ethaddr:mo,"
+#endif
+#endif
+#else
+#define ETHADDR_FLAGS ""
+#endif
+
+#ifndef CONFIG_ENV_OVERWRITE
+#define SERIAL_FLAGS "serial#:so,"
+#else
+#define SERIAL_FLAGS ""
+#endif
+
 #define ENV_FLAGS_LIST_STATIC \
+	ETHADDR_FLAGS \
+	SERIAL_FLAGS \
 	CONFIG_ENV_FLAGS_LIST_STATIC
 
 #ifdef CONFIG_CMD_ENV_FLAGS
diff --git a/tools/env/fw_env.c b/tools/env/fw_env.c
index a596a1b..90c7a5d 100644
--- a/tools/env/fw_env.c
+++ b/tools/env/fw_env.c
@@ -369,23 +369,6 @@ int fw_env_write(char *name, char *value)
 		return 0;
 
 	if (deleting || overwriting) {
-#ifndef CONFIG_ENV_OVERWRITE
-		/*
-		 * Ethernet Address and serial# can be set only once
-		 */
-		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 */
-		   ) ) {
-			fprintf (stderr, "Can't overwrite \"%s\"\n", name);
-			errno = EROFS;
-			return -1;
-		}
-#endif /* CONFIG_ENV_OVERWRITE */
-
 		if (*++nxt == '\0') {
 			*env = '\0';
 		} else {
-- 
1.7.11.5

^ permalink raw reply related	[flat|nested] 124+ messages in thread

* [U-Boot] [PATCH v5 0/20] Add environment call-back and flags capability
  2012-12-12  4:16                                           ` [U-Boot] [PATCH v5 " Joe Hershberger
                                                               ` (19 preceding siblings ...)
  2012-12-12  4:16                                             ` [U-Boot] [PATCH v5 20/20] env: Handle write-once ethaddr and serial# generically Joe Hershberger
@ 2012-12-14 16:05                                             ` Tom Rini
  20 siblings, 0 replies; 124+ messages in thread
From: Tom Rini @ 2012-12-14 16:05 UTC (permalink / raw)
  To: u-boot

On Tue, Dec 11, 2012 at 10:16:17PM -0600, Joe Hershberger wrote:

> When a variable with a registered callback is inserted, deleted, or
> overwritten the callback is called and gives the system an opportunity
> to do something in response to the change.  It also has the opportunuty
> to reject the change by returning non-zero.
> 
> The flags on variables can control their type as well as their allowed
> access.
> 
>         The format of the list is:
>                 type_attribute = [s|d|x|b|i|m]
>                 attributes = type_attribute
>                 entry = variable_name[:attributes]
>                 list = entry[,list]
> 
>         The type attributes are:
>                 s - String (default)
>                 d - Decimal
>                 x - Hexadecimal
>                 b - Boolean ([1yYtT|0nNfF])
>                 i - IP address
>                 m - MAC address
> 
>         The access attributes are:
>                 a - Any (default)
>                 r - Read-only
>                 o - Write-once
>                 c - Change-default
> 
> Changes in v5:
> - Manually relocate change_ok() pointer
> - Add support for CONFIG_NEEDS_MANUAL_RELOC boards
> - Fixed comment typo
> - Fixed callbacks command help
> - Compare current callback against pre-relocation address manually
> - Fixed out-of-bounds array access in env_flags_parse_vartype()
> - Fixed out-of-bounds array access in env_flags_parse_varaccess()
> 
> Changes in v4:
> - Prevent crash on relocation import
> - Fixed help text
> - Add help text for env flags command
> - Add force support to setenv
> - Implement delete
> 
> Changes in v3:
> - Rebase onto Gerlando Falauto's env patches
> - Refactor himport_r() and hsearch_r()'s parameters
> - Split hdelete_r() into the core delete and the validation before
> delete
> - Delete vars on failed insertion
> - Use Marek's linker lists instead of implementing it directly
> - Rebase onto latest master
> - Add flags parameter to callbacks
> - Implement reverse search in env_attr_lookup()
> - Fix space skipping in env_attr_lookup()
> - All errors coming back from hsearch_r() are no longer fatal.  Don't
> abort import on failed ENTER action.
> - Removed checkpatch.pl warning
> 
> Changes in v2:
> - Added much-needed documentation
> - Factored out prevch and nextch in env_attr_lookup()
> 
> Joe Hershberger (20):
>   Make linux kernel string funcs available to tools
>   env: Refactor do_apply to a flag
>   env: Consolidate common code in hsearch_r()
>   env: Refactor apply into change_ok
>   env: Use getenv_yesno() more generally
>   env: Hide '.' variables in env print by default
>   env: Add support for callbacks to environment vars
>   env: Add a command to view callbacks
>   env: Add a bootfile env handler
>   env: Add a baudrate env handler
>   env: Add a loadaddr env handler
>   env: Add a console env handler
>   env: Add a silent env handler
>   env: Add environment variable flags
>   tools/env: Add environment variable flags support
>   env: Add a command to display details about env flags
>   env: Add support for access control to .flags
>   env: Add setenv force support
>   env: Implement the env delete command
>   env: Handle write-once ethaddr and serial# generically
> 
>  README                          |  80 ++++++
>  arch/arm/lib/board.c            |   4 +-
>  arch/m68k/lib/board.c           |   3 +-
>  arch/microblaze/lib/board.c     |   4 +-
>  arch/powerpc/cpu/mpc85xx/mp.c   |   4 +-
>  arch/powerpc/lib/board.c        |   9 +-
>  arch/sparc/lib/board.c          |   3 +-
>  board/Marvell/db64360/db64360.c |  10 +-
>  board/Marvell/db64460/db64460.c |  10 +-
>  board/esd/cpci750/cpci750.c     |  10 +-
>  board/esd/pmc440/cmd_pmc440.c   |   2 +-
>  board/gw8260/gw8260.c           |  10 +-
>  board/prodrive/p3mx/p3mx.c      |  10 +-
>  common/Makefile                 |   6 +
>  common/cmd_nvedit.c             | 406 +++++++++++++++++------------
>  common/console.c                |  75 +++++-
>  common/env_attr.c               | 229 ++++++++++++++++
>  common/env_callback.c           | 144 +++++++++++
>  common/env_common.c             |  61 +++--
>  common/env_dataflash.c          |   2 +-
>  common/env_eeprom.c             |   2 +-
>  common/env_fat.c                |   2 +-
>  common/env_flags.c              | 560 ++++++++++++++++++++++++++++++++++++++++
>  common/env_flash.c              |   4 +-
>  common/env_mmc.c                |   2 +-
>  common/env_nand.c               |   4 +-
>  common/env_nvram.c              |   2 +-
>  common/env_onenand.c            |   2 +-
>  common/env_sf.c                 |   4 +-
>  common/image.c                  |  21 +-
>  doc/README.silent               |  14 +-
>  drivers/serial/serial.c         |  70 +++++
>  include/common.h                |   5 +
>  include/env_attr.h              |  55 ++++
>  include/env_callback.h          |  75 ++++++
>  include/env_default.h           |   8 +
>  include/env_flags.h             | 172 ++++++++++++
>  include/environment.h           |  15 +-
>  include/image.h                 |   1 -
>  include/linux/linux_string.h    |   8 +
>  include/linux/string.h          |   5 +-
>  include/search.h                |  37 ++-
>  lib/Makefile                    |   1 +
>  lib/hashtable.c                 | 244 +++++++++++------
>  lib/linux_string.c              |  51 ++++
>  lib/string.c                    |  39 ---
>  net/net.c                       |  49 ++--
>  tools/env/Makefile              |   3 +
>  tools/env/fw_env.c              |  92 +++++--
>  49 files changed, 2182 insertions(+), 447 deletions(-)
>  create mode 100644 common/env_attr.c
>  create mode 100644 common/env_callback.c
>  create mode 100644 common/env_flags.c
>  create mode 100644 include/env_attr.h
>  create mode 100644 include/env_callback.h
>  create mode 100644 include/env_flags.h
>  create mode 100644 include/linux/linux_string.h
>  create mode 100644 lib/linux_string.c

Applied to u-boot/master, thanks!

-- 
Tom
-------------- next part --------------
A non-text attachment was scrubbed...
Name: not available
Type: application/pgp-signature
Size: 836 bytes
Desc: Digital signature
URL: <http://lists.denx.de/pipermail/u-boot/attachments/20121214/620a9b9d/attachment.pgp>

^ permalink raw reply	[flat|nested] 124+ messages in thread

* [U-Boot] [PATCH v5 07/20] env: Add support for callbacks to environment vars
  2012-12-12  4:16                                             ` [U-Boot] [PATCH v5 07/20] env: Add support for callbacks to environment vars Joe Hershberger
@ 2013-01-11  8:06                                               ` Stefan Roese
  2013-01-14 23:23                                                 ` Joe Hershberger
  0 siblings, 1 reply; 124+ messages in thread
From: Stefan Roese @ 2013-01-11  8:06 UTC (permalink / raw)
  To: u-boot

Hi Joe,

On 12/12/2012 05:16 AM, Joe Hershberger wrote:
> Add support for per-variable callbacks to the "hashtable" functions.

I just noticed using latest master branch that booting on a NOR
flash based board (sequoia, PPC440EPx based) a quite big delay
(1..2 seconds) is added upon env_relocate() (real delay happens
in himport_r()). Digging a bit deeper results in this patch
(170ab11 [env: Add support for callbacks to environment vars])
started this regression:

[ 36.208317] <  0.004802> U-Boot 2013.01-rc1-00385-g170ab11 (Jan 11 2013 - 08:58:59)
[ 36.209012] <  0.000695> 
[ 36.215956] <  0.006944> CPU:   AMCC PowerPC 440EPx Rev. A at 528 MHz (PLB=132 OPB=66 EBC=66 PCI=33 MHz)
[ 36.218730] <  0.002774>        Security/Kasumi support
[ 36.224290] <  0.005560>        Bootstrap Option H - Boot ROM Location I2C (Addr 0x52)
[ 36.229843] <  0.005553>        Internal PCI arbiter enabled, PCI async ext clock used
[ 36.232704] <  0.002861>        32 kB I-Cache 32 kB D-Cache
[ 36.240869] <  0.008165> Board: Sequoia - AMCC PPC440EPx Evaluation Board, Rev. F, PCI-Async=33 MHz
[ 36.242261] <  0.001392> I2C:   ready
[ 36.648652] <  0.406391> DRAM:  256 MiB
[ 36.811658] <  0.163006> Flash: 64 MiB
[ 36.813331] <  0.001673> NAND:  32 MiB

himport_r()

[ 37.808800] <  0.995469> PCI:   Bus Dev VenId DevId Class Int
[ 37.816780] <  0.007980> USB:   Host(int phy) Device(ext phy)
[ 37.820094] <  0.003314> Net:   ppc_4xx_eth0, ppc_4xx_eth1

Here you see the delay in himport_r() is approx 1 second.

And with patch (2598090 [env: Add environment variable flags]) this
delay even grows to 2 seconds:

[  3.096149] <  0.004800> U-Boot 2013.01-rc1-00392-g2598090 (Jan 11 2013 - 08:55:45)
[  3.096853] <  0.000704> 
[  3.103805] <  0.006952> CPU:   AMCC PowerPC 440EPx Rev. A at 528 MHz (PLB=132 OPB=66 EBC=66 PCI=33 MHz)
[  3.106575] <  0.002770>        Security/Kasumi support
[  3.112135] <  0.005560>        Bootstrap Option H - Boot ROM Location I2C (Addr 0x52)
[  3.117683] <  0.005548>        Internal PCI arbiter enabled, PCI async ext clock used
[  3.120548] <  0.002865>        32 kB I-Cache 32 kB D-Cache
[  3.128716] <  0.008168> Board: Sequoia - AMCC PPC440EPx Evaluation Board, Rev. F, PCI-Async=33 MHz
[  3.130099] <  0.001383> I2C:   ready
[  3.536470] <  0.406371> DRAM:  256 MiB
[  3.699894] <  0.163424> Flash: 64 MiB
[  3.701553] <  0.001659> NAND:  32 MiB

himport_r()

[  5.690365] <  1.988812> PCI:   Bus Dev VenId DevId Class Int
[  5.698395] <  0.008030> USB:   Host(int phy) Device(ext phy)
[  5.701709] <  0.003314> Net:   ppc_4xx_eth0, ppc_4xx_eth1


Joe, I didn't dig deeper into these functions and patches. Do you
have an idea why these patches introduce this delay? Can you
reproduce this on one of your boards? Has anybody else noticed
such issues?

Thanks,
Stefan

^ permalink raw reply	[flat|nested] 124+ messages in thread

* [U-Boot] [PATCH v5 07/20] env: Add support for callbacks to environment vars
  2013-01-11  8:06                                               ` Stefan Roese
@ 2013-01-14 23:23                                                 ` Joe Hershberger
  2013-01-15  6:51                                                   ` Stefan Roese
  0 siblings, 1 reply; 124+ messages in thread
From: Joe Hershberger @ 2013-01-14 23:23 UTC (permalink / raw)
  To: u-boot

Hi Stefan,

On Fri, Jan 11, 2013 at 2:06 AM, Stefan Roese <sr@denx.de> wrote:
> Hi Joe,
>
> On 12/12/2012 05:16 AM, Joe Hershberger wrote:
>> Add support for per-variable callbacks to the "hashtable" functions.
>
> I just noticed using latest master branch that booting on a NOR
> flash based board (sequoia, PPC440EPx based) a quite big delay
> (1..2 seconds) is added upon env_relocate() (real delay happens
> in himport_r()). Digging a bit deeper results in this patch
> (170ab11 [env: Add support for callbacks to environment vars])
> started this regression:
>
> [ 36.208317] <  0.004802> U-Boot 2013.01-rc1-00385-g170ab11 (Jan 11 2013 - 08:58:59)
> [ 36.209012] <  0.000695>
> [ 36.215956] <  0.006944> CPU:   AMCC PowerPC 440EPx Rev. A at 528 MHz (PLB=132 OPB=66 EBC=66 PCI=33 MHz)
> [ 36.218730] <  0.002774>        Security/Kasumi support
> [ 36.224290] <  0.005560>        Bootstrap Option H - Boot ROM Location I2C (Addr 0x52)
> [ 36.229843] <  0.005553>        Internal PCI arbiter enabled, PCI async ext clock used
> [ 36.232704] <  0.002861>        32 kB I-Cache 32 kB D-Cache
> [ 36.240869] <  0.008165> Board: Sequoia - AMCC PPC440EPx Evaluation Board, Rev. F, PCI-Async=33 MHz
> [ 36.242261] <  0.001392> I2C:   ready
> [ 36.648652] <  0.406391> DRAM:  256 MiB
> [ 36.811658] <  0.163006> Flash: 64 MiB
> [ 36.813331] <  0.001673> NAND:  32 MiB
>
> himport_r()
>
> [ 37.808800] <  0.995469> PCI:   Bus Dev VenId DevId Class Int
> [ 37.816780] <  0.007980> USB:   Host(int phy) Device(ext phy)
> [ 37.820094] <  0.003314> Net:   ppc_4xx_eth0, ppc_4xx_eth1
>
> Here you see the delay in himport_r() is approx 1 second.
>
> And with patch (2598090 [env: Add environment variable flags]) this
> delay even grows to 2 seconds:
>
> [  3.096149] <  0.004800> U-Boot 2013.01-rc1-00392-g2598090 (Jan 11 2013 - 08:55:45)
> [  3.096853] <  0.000704>
> [  3.103805] <  0.006952> CPU:   AMCC PowerPC 440EPx Rev. A at 528 MHz (PLB=132 OPB=66 EBC=66 PCI=33 MHz)
> [  3.106575] <  0.002770>        Security/Kasumi support
> [  3.112135] <  0.005560>        Bootstrap Option H - Boot ROM Location I2C (Addr 0x52)
> [  3.117683] <  0.005548>        Internal PCI arbiter enabled, PCI async ext clock used
> [  3.120548] <  0.002865>        32 kB I-Cache 32 kB D-Cache
> [  3.128716] <  0.008168> Board: Sequoia - AMCC PPC440EPx Evaluation Board, Rev. F, PCI-Async=33 MHz
> [  3.130099] <  0.001383> I2C:   ready
> [  3.536470] <  0.406371> DRAM:  256 MiB
> [  3.699894] <  0.163424> Flash: 64 MiB
> [  3.701553] <  0.001659> NAND:  32 MiB
>
> himport_r()
>
> [  5.690365] <  1.988812> PCI:   Bus Dev VenId DevId Class Int
> [  5.698395] <  0.008030> USB:   Host(int phy) Device(ext phy)
> [  5.701709] <  0.003314> Net:   ppc_4xx_eth0, ppc_4xx_eth1
>
>
> Joe, I didn't dig deeper into these functions and patches. Do you
> have an idea why these patches introduce this delay? Can you
> reproduce this on one of your boards? Has anybody else noticed
> such issues?

That is far more than I would expect.  Let me have a look at it.
Thanks for bringing this up.

Do you have an extremely large env?

Thanks,
-Joe

^ permalink raw reply	[flat|nested] 124+ messages in thread

* [U-Boot] [PATCH v5 07/20] env: Add support for callbacks to environment vars
  2013-01-14 23:23                                                 ` Joe Hershberger
@ 2013-01-15  6:51                                                   ` Stefan Roese
  0 siblings, 0 replies; 124+ messages in thread
From: Stefan Roese @ 2013-01-15  6:51 UTC (permalink / raw)
  To: u-boot

Hi Joe,

On 01/15/2013 12:23 AM, Joe Hershberger wrote:

<snip>

>> Here you see the delay in himport_r() is approx 1 second.
>>
>> And with patch (2598090 [env: Add environment variable flags]) this
>> delay even grows to 2 seconds:
>>
>> [  3.096149] <  0.004800> U-Boot 2013.01-rc1-00392-g2598090 (Jan 11 2013 - 08:55:45)
>> [  3.096853] <  0.000704>
>> [  3.103805] <  0.006952> CPU:   AMCC PowerPC 440EPx Rev. A at 528 MHz (PLB=132 OPB=66 EBC=66 PCI=33 MHz)
>> [  3.106575] <  0.002770>        Security/Kasumi support
>> [  3.112135] <  0.005560>        Bootstrap Option H - Boot ROM Location I2C (Addr 0x52)
>> [  3.117683] <  0.005548>        Internal PCI arbiter enabled, PCI async ext clock used
>> [  3.120548] <  0.002865>        32 kB I-Cache 32 kB D-Cache
>> [  3.128716] <  0.008168> Board: Sequoia - AMCC PPC440EPx Evaluation Board, Rev. F, PCI-Async=33 MHz
>> [  3.130099] <  0.001383> I2C:   ready
>> [  3.536470] <  0.406371> DRAM:  256 MiB
>> [  3.699894] <  0.163424> Flash: 64 MiB
>> [  3.701553] <  0.001659> NAND:  32 MiB
>>
>> himport_r()
>>
>> [  5.690365] <  1.988812> PCI:   Bus Dev VenId DevId Class Int
>> [  5.698395] <  0.008030> USB:   Host(int phy) Device(ext phy)
>> [  5.701709] <  0.003314> Net:   ppc_4xx_eth0, ppc_4xx_eth1
>>
>>
>> Joe, I didn't dig deeper into these functions and patches. Do you
>> have an idea why these patches introduce this delay? Can you
>> reproduce this on one of your boards? Has anybody else noticed
>> such issues?
> 
> That is far more than I would expect.  Let me have a look at it.
> Thanks for bringing this up.

Thanks.

> Do you have an extremely large env?

Not really. Here a log of this board:

=> printenv
abc=def
...
yyyy=sdfsdfsfd

Environment size: 4141/8187 bytes

Just let me know if I need to do some more tests to help.

Thanks,
Stefan

^ permalink raw reply	[flat|nested] 124+ messages in thread

end of thread, other threads:[~2013-01-15  6:51 UTC | newest]

Thread overview: 124+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2010-04-28  2:07 [U-Boot] Read-only env variables Joe Hershberger
2010-05-06 21:58 ` Wolfgang Denk
2010-05-10  6:30   ` Joe Hershberger
2010-05-10  6:56     ` Wolfgang Denk
2010-05-10 19:16       ` Joe Hershberger
2010-05-10 20:43         ` Wolfgang Denk
2010-05-10 21:33           ` Joe Hershberger
2010-05-11 20:19             ` Craig Millen
2010-05-11 22:03               ` Wolfgang Denk
2010-05-11 22:52                 ` Joe Hershberger
2010-05-12  9:34                   ` Wolfgang Denk
2010-05-12 23:46                     ` Joe Hershberger
2010-06-22 21:18                       ` Wolfgang Denk
2010-06-22 21:49                         ` Joe Hershberger
2010-06-22 22:29                           ` Wolfgang Denk
2012-08-17 20:49                             ` [U-Boot] [PATCH 0/12] Add environment type checking and access control Joe Hershberger
2012-08-17 20:49                               ` [U-Boot] [PATCH 01/12] tools/env: Use a board-specific default env Joe Hershberger
2012-08-23  3:17                                 ` Mike Frysinger
2012-08-23 15:45                                   ` Joe Hershberger
2012-08-17 20:49                               ` [U-Boot] [PATCH 02/12] tools/env: Remove unneeded complexity Joe Hershberger
2012-08-23  3:30                                 ` Mike Frysinger
2012-08-17 20:49                               ` [U-Boot] [PATCH 03/12] tools/env: Don't call env_init() in fw_getenv() Joe Hershberger
2012-08-17 20:49                               ` [U-Boot] [PATCH 04/12] tools/env: Reduce the impact on real-time processes Joe Hershberger
2012-08-23  3:30                                 ` Mike Frysinger
2012-08-23 16:26                                   ` Joe Hershberger
2012-08-23 20:31                                     ` Mike Frysinger
2012-08-17 20:49                               ` [U-Boot] [PATCH 05/12] tools/env: Serialize calls to fw_*env Joe Hershberger
2012-08-23  3:33                                 ` Mike Frysinger
2012-10-03  1:12                                   ` Joe Hershberger
2012-08-17 20:49                               ` [U-Boot] [PATCH 06/12] env: Make the "silent" env var take effect immediately Joe Hershberger
2012-08-23  3:35                                 ` Mike Frysinger
2012-08-17 20:49                               ` [U-Boot] [PATCH 07/12] env: Update serial baudrate in env_relocate() Joe Hershberger
2012-08-17 20:49                               ` [U-Boot] [PATCH 08/12] env: Check for NULL pointer in envmatch() Joe Hershberger
2012-08-17 23:51                                 ` Mike Frysinger
2012-08-17 20:49                               ` [U-Boot] [PATCH 09/12] env: Clarify the cases for env set Joe Hershberger
2012-08-17 20:49                               ` [U-Boot] [PATCH 10/12] env: acl: Add environment variable access control list Joe Hershberger
2012-08-23  3:43                                 ` Mike Frysinger
2012-09-13 20:13                                 ` Wolfgang Denk
2012-09-14  2:24                                   ` Joe Hershberger
2012-09-14 18:42                                     ` Wolfgang Denk
2012-11-01 16:39                                       ` [U-Boot] [PATCH v3 0/18] Add environment call-back and flags capability Joe Hershberger
2012-11-01 16:39                                         ` [U-Boot] [PATCH v3 01/18] Make linux kernel string funcs available to tools Joe Hershberger
2012-11-01 16:39                                         ` [U-Boot] [PATCH v3 02/18] env: Refactor do_apply to a flag Joe Hershberger
2012-11-01 16:39                                         ` [U-Boot] [PATCH v3 03/18] env: Consolidate common code in hsearch_r() Joe Hershberger
2012-11-01 16:39                                         ` [U-Boot] [PATCH v3 04/18] env: Refactor apply into change_ok Joe Hershberger
2012-11-01 16:39                                         ` [U-Boot] [PATCH v3 05/18] env: Use getenv_yesno() more generally Joe Hershberger
2012-11-01 16:39                                         ` [U-Boot] [PATCH v3 06/18] env: Hide '.' variables in env print by default Joe Hershberger
2012-11-02 10:44                                           ` Luka Perkov
2012-11-02 22:23                                             ` Wolfgang Denk
2012-11-01 16:39                                         ` [U-Boot] [PATCH v3 07/18] env: Add support for callbacks to environment vars Joe Hershberger
2012-11-01 16:39                                         ` [U-Boot] [PATCH v3 08/18] env: Add a command to view callbacks Joe Hershberger
2012-11-01 16:39                                         ` [U-Boot] [PATCH v3 09/18] env: Add a bootfile env handler Joe Hershberger
2012-11-01 16:39                                         ` [U-Boot] [PATCH v3 10/18] env: Add a baudrate " Joe Hershberger
2012-11-01 16:39                                         ` [U-Boot] [PATCH v3 11/18] env: Add a loadaddr " Joe Hershberger
2012-11-01 16:39                                         ` [U-Boot] [PATCH v3 12/18] env: Add a console " Joe Hershberger
2012-11-01 16:39                                         ` [U-Boot] [PATCH v3 13/18] env: Add a silent " Joe Hershberger
2012-11-01 16:39                                         ` [U-Boot] [PATCH v3 14/18] env: Add environment variable flags Joe Hershberger
2012-11-01 16:39                                         ` [U-Boot] [PATCH v3 15/18] tools/env: Add environment variable flags support Joe Hershberger
2012-11-01 16:39                                         ` [U-Boot] [PATCH v3 16/18] env: Add a command to display details about env flags Joe Hershberger
2012-11-01 16:39                                         ` [U-Boot] [PATCH v3 17/18] env: Add support for access control to .flags Joe Hershberger
2012-11-01 16:39                                         ` [U-Boot] [PATCH v3 18/18] env: Handle write-once ethaddr and serial# generically Joe Hershberger
2012-11-02 22:40                                         ` [U-Boot] [PATCH v3 0/18] Add environment call-back and flags capability Wolfgang Denk
2012-11-05  0:15                                           ` Joe Hershberger
2012-12-01 19:44                                           ` Joe Hershberger
2012-12-05  1:52                                         ` [U-Boot] [PATCH v4 0/20] " Joe Hershberger
2012-12-05  1:52                                           ` [U-Boot] [PATCH v4 01/20] Make linux kernel string funcs available to tools Joe Hershberger
2012-12-05  1:52                                           ` [U-Boot] [PATCH v4 02/20] env: Refactor do_apply to a flag Joe Hershberger
2012-12-05  1:52                                           ` [U-Boot] [PATCH v4 03/20] env: Consolidate common code in hsearch_r() Joe Hershberger
2012-12-05  1:52                                           ` [U-Boot] [PATCH v4 04/20] env: Refactor apply into change_ok Joe Hershberger
2012-12-05  1:52                                           ` [U-Boot] [PATCH v4 05/20] env: Use getenv_yesno() more generally Joe Hershberger
2012-12-05  1:52                                           ` [U-Boot] [PATCH v4 06/20] env: Hide '.' variables in env print by default Joe Hershberger
2012-12-05  1:52                                           ` [U-Boot] [PATCH v4 07/20] env: Add support for callbacks to environment vars Joe Hershberger
2012-12-05  2:34                                             ` Graeme Russ
2012-12-05  1:52                                           ` [U-Boot] [PATCH v4 08/20] env: Add a command to view callbacks Joe Hershberger
2012-12-05  1:52                                           ` [U-Boot] [PATCH v4 09/20] env: Add a bootfile env handler Joe Hershberger
2012-12-05  1:52                                           ` [U-Boot] [PATCH v4 10/20] env: Add a baudrate " Joe Hershberger
2012-12-05  1:52                                           ` [U-Boot] [PATCH v4 11/20] env: Add a loadaddr " Joe Hershberger
2012-12-05  1:52                                           ` [U-Boot] [PATCH v4 12/20] env: Add a console " Joe Hershberger
2012-12-05  1:52                                           ` [U-Boot] [PATCH v4 13/20] env: Add a silent " Joe Hershberger
2012-12-05  1:52                                           ` [U-Boot] [PATCH v4 14/20] env: Add environment variable flags Joe Hershberger
2012-12-05  1:52                                           ` [U-Boot] [PATCH v4 15/20] tools/env: Add environment variable flags support Joe Hershberger
2012-12-05  1:52                                           ` [U-Boot] [PATCH v4 16/20] env: Add a command to display details about env flags Joe Hershberger
2012-12-05  1:52                                           ` [U-Boot] [PATCH v4 17/20] env: Add support for access control to .flags Joe Hershberger
2012-12-05  1:52                                           ` [U-Boot] [PATCH v4 18/20] env: Add setenv force support Joe Hershberger
2012-12-05  1:52                                           ` [U-Boot] [PATCH v4 19/20] env: Implement the env delete command Joe Hershberger
2012-12-05  1:52                                           ` [U-Boot] [PATCH v4 20/20] env: Handle write-once ethaddr and serial# generically Joe Hershberger
2012-12-11 16:51                                           ` [U-Boot] [PATCH v4 0/20] Add environment call-back and flags capability Tom Rini
2012-12-12  4:16                                           ` [U-Boot] [PATCH v5 " Joe Hershberger
2012-12-12  4:16                                             ` [U-Boot] [PATCH v5 01/20] Make linux kernel string funcs available to tools Joe Hershberger
2012-12-12  4:16                                             ` [U-Boot] [PATCH v5 02/20] env: Refactor do_apply to a flag Joe Hershberger
2012-12-12  4:16                                             ` [U-Boot] [PATCH v5 03/20] env: Consolidate common code in hsearch_r() Joe Hershberger
2012-12-12  4:16                                             ` [U-Boot] [PATCH v5 04/20] env: Refactor apply into change_ok Joe Hershberger
2012-12-12  4:16                                             ` [U-Boot] [PATCH v5 05/20] env: Use getenv_yesno() more generally Joe Hershberger
2012-12-12  4:16                                             ` [U-Boot] [PATCH v5 06/20] env: Hide '.' variables in env print by default Joe Hershberger
2012-12-12  4:16                                             ` [U-Boot] [PATCH v5 07/20] env: Add support for callbacks to environment vars Joe Hershberger
2013-01-11  8:06                                               ` Stefan Roese
2013-01-14 23:23                                                 ` Joe Hershberger
2013-01-15  6:51                                                   ` Stefan Roese
2012-12-12  4:16                                             ` [U-Boot] [PATCH v5 08/20] env: Add a command to view callbacks Joe Hershberger
2012-12-12  4:16                                             ` [U-Boot] [PATCH v5 09/20] env: Add a bootfile env handler Joe Hershberger
2012-12-12  4:16                                             ` [U-Boot] [PATCH v5 10/20] env: Add a baudrate " Joe Hershberger
2012-12-12  4:16                                             ` [U-Boot] [PATCH v5 11/20] env: Add a loadaddr " Joe Hershberger
2012-12-12  4:16                                             ` [U-Boot] [PATCH v5 12/20] env: Add a console " Joe Hershberger
2012-12-12  4:16                                             ` [U-Boot] [PATCH v5 13/20] env: Add a silent " Joe Hershberger
2012-12-12  4:16                                             ` [U-Boot] [PATCH v5 14/20] env: Add environment variable flags Joe Hershberger
2012-12-12  4:16                                             ` [U-Boot] [PATCH v5 15/20] tools/env: Add environment variable flags support Joe Hershberger
2012-12-12  4:16                                             ` [U-Boot] [PATCH v5 16/20] env: Add a command to display details about env flags Joe Hershberger
2012-12-12  4:16                                             ` [U-Boot] [PATCH v5 17/20] env: Add support for access control to .flags Joe Hershberger
2012-12-12  4:16                                             ` [U-Boot] [PATCH v5 18/20] env: Add setenv force support Joe Hershberger
2012-12-12  4:16                                             ` [U-Boot] [PATCH v5 19/20] env: Implement the env delete command Joe Hershberger
2012-12-12  4:16                                             ` [U-Boot] [PATCH v5 20/20] env: Handle write-once ethaddr and serial# generically Joe Hershberger
2012-12-14 16:05                                             ` [U-Boot] [PATCH v5 0/20] Add environment call-back and flags capability Tom Rini
2012-08-17 20:49                               ` [U-Boot] [PATCH 11/12] env: acl: Add support for access control to env ACL Joe Hershberger
2012-08-17 20:49                               ` [U-Boot] [PATCH 12/12] env: cosmetic: Consilidate the default env definition Joe Hershberger
2012-08-23  3:44                                 ` Mike Frysinger
2012-10-03 19:38                               ` [U-Boot] [PATCH v2 0/5] Cleanup fw_*env and a few common env Joe Hershberger
2012-10-03 19:38                                 ` [U-Boot] [PATCH v2 1/5] tools/env: Use a board-specific default env Joe Hershberger
2012-10-03 19:38                                 ` [U-Boot] [PATCH v2 2/5] tools/env: Remove unneeded complexity Joe Hershberger
2012-10-03 19:38                                 ` [U-Boot] [PATCH v2 3/5] tools/env: Don't call env_init() in fw_getenv() Joe Hershberger
2012-10-03 19:38                                 ` [U-Boot] [PATCH v2 4/5] tools/env: Serialize calls to fw_*env Joe Hershberger
2012-10-03 23:24                                   ` uboot at lukaperkov.net
2012-10-04 18:31                                     ` [U-Boot] [PATCH] tools: Add a README note about fw_printenv lock file Joe Hershberger
2012-10-03 19:38                                 ` [U-Boot] [PATCH v2 5/5] env: Check for NULL pointer in envmatch() Joe Hershberger
2012-10-09 17:13                                 ` [U-Boot] [PATCH v2 0/5] Cleanup fw_*env and a few common env Tom Rini

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.