Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Reading the linux utmp file without using fopen() and fread()

Tags:

c

file

linux

I am trying to open the utmp file in Linux and read the contents into an array of utmp structures. After that I display the ut_user and ut_type from each structure in the array. I have this working when I open the file with File *file and use the fopen() and fread() functions but when I try to do the same task with just a file descriptor int file and the open() and read() functions I get address locations when trying to access members of the utmp structure.

So in the below program you can see I commented out three lines of code which together I could use to successfully perform the task of reading the utmp file into an array of utmp structures and print out two of their members values. But when I try doing the exact same thing with the three lines of code (denoted "new way") in place of the old way that worked I get a bunch of address locations rather than the values of ut_user and ut_id.

    #include <unistd.h>
    #include <sys/stat.h>
    #include <fcntl.h>
    #include <stdlib.h>
    #include <stdio.h>
    #include <string.h>
    #include <utmp.h>


    void utmpprint(struct utmp *log) {

        printf("\n ut_user: %s \n ut_type: %ld \n", log->ut_user, log->ut_type);
    }


    int main() {

        int logsize = 10;

        //FILE *file;        //Working way
        int file;            //New way

        struct utmp log[logsize];
        int i = 0;

        //file = fopen("/var/run/utmp", "rb");   //Working way
        file = open("/var/run/utmp", O_RDONLY);  //New way

        if( file < 0 ) {  //New way
           printf("Failed to open");
           return(0);
        }

        if (file) {

                //fread(&log, sizeof(struct utmp), logsize, file);  //Working way
                read(file, &log, logsize);                          //New way

                for(i = 0; i < logsize; i++) {

                        utmpprint(&log[i]);
                }

                close(file);     //New way

        } else {
                return(0);
        }

        return(0);
    }

Here is some of the output for the working way:

enter image description here

And here is the output for the new way that is not working:

enter image description here

I have tried looking online for more information on this matter but I can't seem to find anything that uses the file descriptor and not File. I also tried changing around some of the pointers and references but that did not improve any of the results.

I am very new to C and I think I am probably using the read() function incorrectly in this case because I am passing a simple buffer into the read function when I think I should be somehow passing it the utmp structure array.

like image 461
Kyle Bridenstine Avatar asked Feb 02 '26 04:02

Kyle Bridenstine


2 Answers

You are not reading enough data from the file.

read(file, &log, logsize);

should be:

read(file, &log, sizeof(log));
// or
read(file, &log, logsize * sizeof (struct utmp));

Also, in both cases, you should check the return value to see how many bytes were actually read.

like image 64
MByD Avatar answered Feb 05 '26 07:02

MByD


Even though you could manipulate data from the utmp file by using the open() system call or functions derived from open(), it is impractical.

You could include the "utmp.h" header in your project and use predefined functions and data structures.

Here you can find the utmp.h file documentation.

Below is some code to print the ut_user and ut_type using the utmp.h data structures and functions.

#include <utmp.h>
#include <stdio.h>
#include <string.h>
int main()
{
    struct utmp* data;
    char aux[50];
    data = getutent();
    //getutent() populates the data structure with information 
    while(data != NULL )
    {
        /*make sure to use strncpy 
         *because most data fiels in the utmp struct 
         *have ___nonstring___ atribute */
        strncpy(aux, data->ut_user, 32);
                aux[32] = '\0';
        printf("ut_user: %s\n", aux);
        printf("ut_type: %hi\n\n", data->ut_type);
        data = getutent();
    }
    return 0;
}

The output of the code is:

ut_user: reboot
ut_type: 2
    
ut_user: alc
ut_type: 7
    
ut_user: runlevel
ut_type: 1
like image 45
Alex Lazar Avatar answered Feb 05 '26 07:02

Alex Lazar



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!