[Toybox] [CLEANUP] More thoughts on stat.c cleanup.

Rob Landley rob at landley.net
Thu May 30 20:46:29 PDT 2013


Sigh, my idea from the other night didn't pan out. I was hoping that I  
could always pass a long to xprintf(), and then just store the xprintf  
format string and a pointer to the value, dereference it as a long *,  
and let xprintf figure out how much of the stack to consume. (The  
endianness should work out either way, and padding isn't an issue when  
you only have one value.)

The problem is alignment: arm64 can't read a long from an int-aligned  
address. 8 byte types need 8 byte alignment, not 4. Blah.

What I really want is some variant of vprintf() that can start reading  
values from a pointer location instead of a va_list. Unfortunately,  
libc hasn't got one. Nor has it got "I passed you a pointer,  
dereference it" notation from the actual printf logic that knows the  
size of the data type...

Ok, I need to collate the "long" and "long long" types into two printf  
groups. And isolate the stuff with extra processing....

Hang on, this is wrong:

     case 'X':
       xprintf("%llu", stat->st_atime);

That's just "long", not "long long". (In the kernel source, see  
arch/include/uapi/asm/stat.h, definition of struct stat _and_ struct  
stat64, it's unsigned long in both. I have no idea why st_mtime_nsec is  
"int", but int and long are equivalent on 32 bit x86 so it's just weird  
and not actually incorrect.)

And that's the problem: on a 32 bit system, long is the same size as  
int, not as uint64_t. How on earth does that work? (Is gcc promoting  
the type...?)

   $ CFLAGS="--static -Wall"  
CROSS_COMPILE=~/cross-compiler-i686/bin/i686- make
   $ stat -c %Y /
   1368946682
   $ ./toybox stat -c %Y /
   104448161786

So that's a no, then. It's just buggy.

Ok, how portable is that type?

   $ grep "st_mtime;"  arch/*/include/uapi/asm/stat.h \
     | sed 's/^.*://;s/[ \t][ \t]*/ /g' | sort -u
   int st_mtime; /* Time of last modification. */
   signed int st_mtime;
   time_t st_mtime;
   unsigned int st_mtime;
   unsigned long st_mtime;
   unsigned long st_mtime; /* Time of last modification. */

Apparently not. What size is time_t anyway? It's __kernel_time_t. Which  
is...

   $ find $(find . -name uapi) -name "*.h" | xargs grep __kernel_time_t  
| grep typedef
   ./include/uapi/asm-generic/posix_types.h:typedef __kernel_long_t	 
__kernel_time_t;
   $ find $(find . -name uapi) -name "*.h" | xargs grep __kernel_long_t  
| grep typedef
   ./arch/x86/include/uapi/asm/posix_types_x32.h:typedef long long  
__kernel_long_t;
   ./include/uapi/asm-generic/posix_types.h:typedef long		 
__kernel_long_t;

They special cased 32 bit x86 and nobody else did. Bravo. So 32 bit arm  
still has a 2038 problem? (What?)

Right. Looks like I have to hit it with a typecast, _and_ I might have  
to check the other types to see if they match up with what printf  
expects...

Lemme get back to this one. :)

Rob


More information about the Toybox mailing list