2

I am working on an embedded Linux system (kernel-5.10.24), which is a 32bit system, and it is using GLibc-2.38 to fix Y2k38.

The rootfs is built from buildroot rel.2023-aug with Y2k38 fix. (built with -D_TIME_BITS=64 -D_FILE_OFFSET_BITS=64 -D_LARGEFILE_SOURCE -D_LARGEFILE64_SOURCE).

There are getty and login built from busybox-1.36.1 in the buildroot.

Now I found strange things when I tried to read the /var/run/utmp with following codes (also built with -D_TIME_BITS=64 -D_FILE_OFFSET_BITS=64 -D_LARGEFILE_SOURCE -D_LARGEFILE64_SOURCE).

#include <stdio.h> #include <utmp.h> #include <time.h> #include <string.h> int main() { FILE *fp; struct utmp ut; printf("XXXXXXXXX sizeof utmp: %ld\n", sizeof(ut)); fp = fopen("/var/run/utmp", "r"); if (fp == NULL) { perror("Error opening UTMP file"); return 1; } while (fread(&ut, sizeof(struct utmp), 1, fp) == 1) { if (ut.ut_type == USER_PROCESS) { printf("Login Name: %s\n", ut.ut_user); printf("Login Time: %s", ctime(&ut.ut_tv.tv_sec)); } } fclose(fp); return 0; } 

When root is logged in and run the code, it showed,

# /tmp/utmpread XXXXXXXXX sizeof utmp: 400 

But the size of /var/run/utmp is 384.

# stat /var/run/utmp File: /var/run/utmp Size: 384 Blocks: 8 IO Block: 4096 regular file Device: fh/15d Inode: 8 Links: 1 Access: (0644/-rw-r--r--) Uid: ( 0/ root) Gid: ( 0/ root) Access: 1970-01-01 01:14:24.270002128 +0000 Modify: 1970-01-01 00:03:12.000000000 +0000 Change: 1970-01-01 01:12:47.210002082 +0000 

So based on my tests, it seemed that struct utmp is already built as 64bit of timeval_t, and the login and getty also report its size is 400Bytes.
But the size of /var/run/utmp is still 384 Bytes, which is using 32bit timeval_t.

I don't know why there is the mismatch (the code reports size of struct utmp is 400, but the file generated from struct utmp is 384), is it from the GLIBC or from the busybox?

Thanks,

1 Answer 1

1

I found a solution to read /var/run/utmp correctly by referring to who.c in busybox.

 struct utmp *ut; setutent(); while ((ut = getutent()) != NULL) { if (ut->ut_type == USER_PROCESS) { if (strcmp(ut->ut_user, "root") == 0) { printf("root logged in\n"); } } } endutent(); ... 

But the question is still valid, why the sizes are different?

10
  • I don't have a way to confirm this, and my last C programming was really decades ago, but when you run struct utmp *ut you are only declaring space for a particular structure, so when you say sizeof(ut) you getting the size of the declared data structure. You need to run a function to "populate" that structure with values, which you are now doing in you answer code. My assumption is that now that the structure has data populated, it size has changed and that seems normal. Any allocated space for char arrays are now zero terminated strs and that would affect the size of the struct reprted. Commented Mar 8, 2024 at 5:15
  • That is to say, if the structure has room for a 60 char string, and you only use 40, that would reduce the reported size. Learn to use dbg (the debugger) and how to inspect these things (-; .... ALSO, depending on OS, the struct may be "zeroed-out" where all elements are completely populated with NUL, and as you run the init/population function, that will use real live data, which (likely) will report a different size. Commented Mar 8, 2024 at 5:16
  • I did another test with the same codes, but without those 64bit options for compiling. This time, the size of struct utmp is 384, the same size as the file. And by dumping the /var/run/utmp, I found there are more trailing 0, I am not sure if there is any other zeroed-out happened when the struct utmp is fully written to disk file. Commented Mar 8, 2024 at 6:47
  • 1) So you now have matching sizes reported. Case closed? 2) Did you have a problem you were trying to fix besides "sizes don't match"? If yes, then post a new question after reading [mcve]. 3) Do you know about std C lang string termination with NUL (0)? 4) gdb is debugger installed with the gcc compiler, but as you're doing busybox, there may be a different compiler/debugger you have to use. Find a tutorial about using that debugger and dig in (-;! 5) Good luck. Commented Mar 8, 2024 at 15:49
  • No no, my answer is just a way (correct way) to read /var/run/utmp, but it still did NOT answer the original question on the mismatch of struct utmp and file of /var/run/utmp. So it still needs more investigation. I can build gdb for this embedded system, but I am not sure if gdb can help in debugging the GLIBC code (I think the mismatch come from the GLIBC), which calls write behind endutent(). Commented Mar 9, 2024 at 12:30

You must log in to answer this question.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.