0

I'm trying to write a simple "ls" script in C in bash (linux). I managed to write a script that gives me all information that I need about files in given directory, However, for some reason it works only for current "." directory, and not for any other. For any other directory it shows files inside (for example file names are correct), but doesn't show correct stats (additional information about files). I have no clue how to repair it. As a guide I used http://man7.org/linux/man-pages/man2/stat.2.html.

My script:

#include <unistd.h>
#include <stdlib.h>
#include <stdio.h>
#include <dirent.h>
#include <sys/types.h>
#include <sys/stat.h> 

int main(int argc, char *argv[]) {
  int opt;
  DIR *dir;
  struct dirent *poz;
  char *katalog;
  char *nazwa, *user_n, *grupa_n, *rozmiar_n, *numer_iw, *typ_p, *output_p;
  nazwa = "Name"; user_n = "UID"; grupa_n = "GID", rozmiar_n = "Size"; numer_iw = "I-node no."; typ_p = "Type"; 
  struct stat sb;

    if (argc == 2) {
    katalog = argv[1];
    dir = opendir(katalog);
    printf("%11s %11s %11s %11s %11s %15s \n", typ_p, user_n, grupa_n, numer_iw, rozmiar_n, nazwa);

    if (dir) {      while ((poz = readdir(dir)) != NULL) {

        if (lstat(poz->d_name, &sb) == 1) {
          perror("lstat");
          exit(EXIT_FAILURE);
        }

           switch (sb.st_mode & S_IFMT) {
           case S_IFBLK:  output_p = "block device";            break;
           case S_IFCHR:  output_p = "character device";        break;
           case S_IFDIR:  output_p = "directory";               break;
           case S_IFIFO:  output_p = "FIFO";                    break;
           case S_IFLNK:  output_p = "symlink";                 break;
           case S_IFREG:  output_p = "file";                    break;
           case S_IFSOCK: output_p = "socket";                  break;
           default:       output_p = "unknown";                 break;
}

  printf("%11s %11llu %11llu %11llu %11llu %15s \n", output_p, (unsigned long long) sb.st_gid, 
  (unsigned long long) sb.st_uid, (unsigned long long) sb.st_ino, (unsigned long long) sb.st_size, poz->d_name);

      }
      closedir(dir);
    }

  }

  return (0);
}

Sample execution:

./a.out .

Works fine (output):

       Type         UID         GID  I-node no.        Size            Name 
       file        1000        1000      274621         248    sample_file2 
       file        1000        1000      274603          36     sample_file 
       file        1000        1000      272921       12776           a.out 
       file        1000        1000      274616        1859        script.c 
  directory        1000        1000      295524        4096               . 
  directory        1000        1000      269568        4096              .. 
  directory        1000        1000      295526        4096      sample_dir 

Sample execution:

./a.out sample_dir

Works with errors (wrong information, e.g. file type or size is wrong for all files/directories):

       Type         UID         GID  I-node no.        Size            Name 
  directory        1000        1000      295524        4096               . 
  directory        1000        1000      295524        4096 sample_file_inside_dir 
  directory        1000        1000      295524        4096 sample_dir_inside_dir 
  directory        1000        1000      295524        4096   sample_file_2 
  directory        1000        1000      269568        4096              .. 

I can't see where is this error... Why stat() works properly only for current directory? Is there a way to change it?

Thank you for your time. B

BloodyMary
  • 173
  • 13
  • Why are you comparing `lstat()`'s return value to 1? Read the man page to see what it returns. – Shawn Nov 18 '18 at 20:56
  • stat() needs the full (absolute,or relative to the current directory) pathname – wildplasser Nov 18 '18 at 20:56
  • @Shawn when I'm using "-1" as is shown here http://man7.org/linux/man-pages/man2/stat.2.html I get an error that no such file or directory exists (even if it exists). With "1" it just works, but as you can see, without the proper additional information. – BloodyMary Nov 18 '18 at 20:59
  • 1
    @wildplasser But it is a relative pathname when I'm calling the script as "./a sample_dir", same as "cd sample_dir". This directory is in fact in the same directory as my script. It should work I guess. Or maybe you had something else on your mind? – BloodyMary Nov 18 '18 at 21:02
  • 1
    "No such file or directory" is correct. Your `lstat` calls are failing and you're printing uninitialized variables. – melpomene Nov 18 '18 at 21:09
  • OK. I found it. THAT'S THE ANSWER FOR ANYONE LOOKING FOR THE SAME BUG: chdir(catalog); need to be added before readdir(); and everything works fine. Because the topic was closed for any reason, I'm putting the answer here for any other lost souls :). – BloodyMary Nov 18 '18 at 21:15
  • Beware of using `chdir()`; it can be hard to get back to where you started for the next directory. – Jonathan Leffler Nov 18 '18 at 21:48

0 Answers0