[Toybox] [take 2] Ifconfig cleanup: bonus round!

Rob Landley rob at landley.net
Fri Nov 29 22:28:27 PST 2013


Now with (hopefully) less broken wordwrapping. (Thanks balsa! You're a  
horrid email client.)

http://landley.net/hg/toybox/rev/1127

My ifconfig cleanups stalled a while back when I got derailed doing  
ipv6 research, an area I'm not that familiar with because I don't  
personally use it. But the musl-libc has some ipv6 address tests that  
got me looking at this area again, so:

display_ifconfig():

The fopen("/proc/net/if_net6") has wrong whitespace (while() with  
function spacing instead of flow control statement spacing, and no  
blank line between the variable declarations and non-declaration code),  
which I leave as a hint to myself that I need to look at this area more  
deeply.

No need to zero iface_name[] during its declaration if the sscanf() is  
going to initialize it. Similarly, nitems is overwritten a couple lines  
after initialization.

The fgets() is reading a structure parsed by sscanf() which has to have  
32+8+2+2+2+15 plus 6 whitespace characters for a grand total well under  
128. So using the whole of toybuf is probably overkill...

Don't need "sizeof(ipv6_addr) / (sizeof ipv6_addr[0])" because  
ipv6_addr is a char and we know how big a char is.

Unwind the if (nitems = 4) block because it's 4 lines and two separate  
if statements can be two lines. (Shorter code that isn't significantly  
more complex is generally a win.) Similarly, collate the two int  
variable declarations onto the same line, which is still nowhere near  
80 characters... except we've already got an "int i" in the enclosing  
scope, so that declaration is redundant.

char *p; has too large a scope to grep for where it's used, so rename  
to pp. Then reuse it in the fopen() to copy the path and use the  
pathname in the perror_exit().

Redo the ipv6_addr read to be the start of the string and count down  
instead of up inserting the colons. That way we can do &3 instead of  
%5, and as a bonus it copies the existing string's null terminator.  
(The if () if () is because even though I _think_ && is a sequence  
point so (i++ && i) is deterministic, I'm not _sure_. I know if (i++)  
if (i) is.)

I'm still a little iffy about the inet_pton()/inet_ntop() pair there.  
We're parsing the a set of 32 hex digits itno a colon separated string,  
converting it to a binary address, and then converting that _back_ into  
ipv6. I'm aware that this squishes runs of zeroes and does the ::  
thing, but as long as we're parsing anyway it might be better for us to  
do that ourselves.

Now the potential reason to use inet_ntop() is that squishing the first  
run of zeroes into :: is trivial but squishing the LONGEST run of  
zeroes isn't. (Or at least requires two passes.)

Let's see, how do zero runs squish in practice...

   $ sudo ifconfig eth0 add 1:2:3:4:5:6:7:8:9:ff
   1:2:3:4:5:6:7:8:9:ff: Resolver Error 0 (no error)

Oh hey, that's nice. (Ubuntu 12.04 does that. People haven't really  
debugged ipv6 much, have they?)

   $ ifconfig eth0 add 0:2:3:4:5:6:7:ff
   $ ifconfig eth0 add 0:0:3:4:5:6:7:ff
   $ ifconfig eth0 add 1:0:3:4:5:6:7:ff
   $ ifconfig eth0 add 1111:2222:3333:4444:555:66:7:ff
   $ ifconfig eth0
   eth0      Link encap:Ethernet  HWaddr dc:0e:a1:52:92:77
             inet6 addr: 1111:2222:3333:4444:555:66:7:ff/128  
Scope:Global
             inet6 addr: 1:0:3:4:5:6:7:ff/128 Scope:Global
             inet6 addr: ::3:4:5:6:7:ff/128 Scope:Global
             inet6 addr: 0:2:3:4:5:6:7:ff/128 Scope:Global

Um, the toybox one isn't printing any inet6 addresses? Ah, because it's  
looking for /proc/net/if_net6 and the file is if_inet6 with an i. (My  
bad, sorry. I broke it in an earlier cleanup round and had no ipv6  
tests ready. Trying to rectify that now...)

Anyway, the zero eliding behavior is complicated enough that relying on  
libc to do it for us is probably a good idea, so let's make it work:

The next reason we get no ipv6 output is display_ifconfig() is called  
from show_iface() with an argument that lives in toybuf, and then we  
overwrite toybuf so the strcmp(name, iface_name) never triggers. Easy  
fix: change the display_ifconfig() call from show_iface() to use the  
variable that lives in argv[] instead of the one that lies in toybuf.

   if (inet_pton(AF_INET6, ipv6_addr, (void *)&sock_in6.sin6_addr) > 0)  
{
     sock_in6.sin6_family = AF_INET6;
     if (inet_ntop(AF_INET6, &sock_in6.sin6_addr, toybuf,  
sizeof(toybuf))) {

Riiiight. so we parse it as AF_INET6, we set AF_INET6 in the struct,  
and then we feed AF_INET6 to the expansion function. Do we really need  
all three? (Tries commenting out the middle one... still seems to work.)

Don't need an int j; if int i isn't used in scope here...

Ok, that's probably enough for one pass.

Rob


More information about the Toybox mailing list