简体   繁体   中英

Linux “ls -al” like program in C

I have for homework to write a C program, which is acting like the Linux "ls -al" command. I know that there are a lot of example programs over the internet, which are doing the thing that I need, but I have a specific problem, to which I can't find a solution. I also want to mention, that I am new to C programming. Here is my code :

#include <stdio.h>
#include <stdlib.h>
#include <dirent.h>
#include <errno.h>
#include <string.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
#include <time.h>
#include <pwd.h> 

int list_dir(const char *dirname)     { 

struct dirent* current_directory;
struct stat my_stat;
struct tm lt;  
struct passwd *pwd; // For User-ID

DIR* directory = opendir(dirname);


    if(directory == NULL)     { 

    printf("list_dir : %s : %s \n", dirname, strerror(errno));

    return 0;
}   

    printf("Directory : %s\n", dirname);
    printf("\n");

    while( (current_directory = readdir(directory) ) )     { 

    stat(current_directory->d_name, &my_stat);  

        if ( (stat(current_directory->d_name, &my_stat) ) == 0 )    {

        pwd = getpwuid(my_stat.st_uid); // Get User-ID

    }

        // Last Modified 
        time_t t = my_stat.st_mtime;
        localtime_r(&t, &lt);
        char timebuf[80];
        strftime(timebuf, sizeof(timebuf), "%c", &lt);

        if (pwd != 0) {

        printf("%s \t %ld \t %s \t %s", pwd->pw_name, (long)my_stat.st_size, timebuf, current_directory->d_name);
        printf("\n");

        } else  {

            printf("%d \t %ld \t %s \t %s", my_stat.st_uid, (long)my_stat.st_size, timebuf, current_directory->d_name);
            printf("\n");
        } 
}
    closedir(directory);        

    return 0; 
}

int main(int argc, char* argv[])    {

    if ( argc == 1 ) {

    return list_dir ( "." );

    } else {

    int ret = 0;

    for (int i = 1; i < argc; i += 1 ) {

        if ( list_dir ( argv[i] ) != 0 ) {

        ret = 1; 
        }
    }

    return ret;
     } 
} 

The program has to display the same things (without the permissions) as "ls -al". So far so good, if I compile it with "gcc -std=gnu99 -o list_dir list_dir.c" and execute the program with "./list_dir" I am getting the same result as "ls -al" and it looks like this :

 username    1599    Fri May  1 20:43:57 2015    list_dir.c

However if I run the program with something like : "./list_dir /home/username/Downloads/" I am getting this :

 32727   0   Sun May  8 07:09:04 4461391     selection_sort.c

As you can see, the program can't get the right information about the Username, the size of the file and the year. Also this information is appearing thanks to the else case of the if(pwd != 0) statement. If I don't have the else case, the program is printing out only the files, for which it can get the correct information. Also if I remove this if statement and also the if statement :

 if ( (stat(current_directory->d_name, &my_stat) ) == 0 )

I am getting a segmentation fault.

So my questions are : 1.What am I doing wrong. I know that I am doing something wrong, because as a hint for the homework I have an example run of the program and also a hint that I can use "stat, lstat, readlink, getpwnam, getpwuid, strftime".

2.Is there any way to get the username with stat() and with the User-ID only, or it's only possible with getpwuid?

Here,

    if ( (stat(current_directory->d_name, &my_stat) ) == 0 ) {
       pwd = getpwuid(my_stat.st_uid); // Get User-ID
    }

What happens if stat() fails? pwd would have uninitialized value or incorrect value set from previous iteration.

The reason why stat would fail, current_directory->d_name contains only the file name whereas stat expects a fullpath. So you need to prepend the directory name to the file and pass it to stat() . You are only passing the filename right now.

Something like:

   char buf[1024];
   errno = 0;
   snprintf(buf, sizeof buf, "%s/%s", dirname, current_directory->d_name);
   if ( (stat(buf, &my_stat) ) == 0 ) {
     ...
   }
   else {
      printf("%s: %s\n", buf, strerror(errno));
      // exit here or continue to the next entry in the directory 
      //depending how you wish to handle failure
   }

and handle the error in case stat() fails.

You also have one other stat() inside the loop which doesn't do anything.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM