-1

I would like to write a simple C script in UNIX that will work like "ls -l". I have a working part where the script lists all of the files in the current directory:

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

int main(int argc, char *argv[])
{
 DIR *katalog;
 struct dirent *dir;
 katalog = opendir(".");

if (argc == 1) {
printf("without option");
  if (katalog) {
    while ((dir = readdir(katalog)) {
     printf("%s \n", dir->d_name);
    }
    closedir(katalog);
  }
  return(0);
}    
}

Now I wanted to add information about the st_gid, st_uid, st_size and st_mtime. I stared from st_uid. My code looks like that now (it's compiling well under unix). Unfortunely, it gives me an error "Segmentation fault (core dumped)". I tried to look for the answer in the Stack and Internet, and I even used some hints from other threads (for example: C format issue with printf("%d", astatbuff->st_size);), but still the error occurs... I don't know what more I can change to repair it...

Here's the code that produces the error:

#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[])
{
 DIR *katalog;
 struct dirent *dir;
 katalog = opendir(".");
 struct stat *astat;

if (argc == 1) {
printf("Without option");
  if (katalog) {
    while ((dir = readdir(katalog)) != NULL && astat->st_uid != 0) {
     printf("%s %llu \n", dir->d_name, (unsigned long long)astat->st_uid);
    }
    closedir(katalog);
  }
  return(0);
}
}
BloodyMary
  • 173
  • 13
  • 1
    Productivity tip: Enable all compiler warnings and _save time_. My compiler reported "warning: 'astat' may be used uninitialized in this function". – chux - Reinstate Monica Nov 18 '18 at 13:56
  • @chux How to do that? How to enable compiler warnings under Unix? I'm just simply using command line and "cc" compiler. It doesn't give my any warnings hints. – BloodyMary Nov 18 '18 at 13:57
  • Perhaps `gcc -std=c11 -O3 -pedantic -Wall -Wextra -Wconversion ...`. Research you compiler doc for more info. – chux - Reinstate Monica Nov 18 '18 at 13:59
  • See [Sample function using `struct stat`](http://man7.org/linux/man-pages/man2/stat.2.html) – chux - Reinstate Monica Nov 18 '18 at 14:03
  • @chux I trided to compile it with "cc" and "gcc" and it doesn't give any warnings. Code is compiling OK, but when I try run ./a.out it gives the error... I will try to search for these "extra" warninings... – BloodyMary Nov 18 '18 at 14:09
  • The particular gcc waring arrives via `-Wmaybe-uninitialized`. I thought that was also enabled via `-pedantic -Wall -Wextra -Wconversion`. You could append that option explicitly too. Much depends on gcc version. Good luck! – chux - Reinstate Monica Nov 18 '18 at 14:13
  • @chux Actually, I tried it with "-Wmaybe-uninitialized" and also with "-Wuninitialized" and "-Wextra" (https://gcc.gnu.org/onlinedocs/gcc-3.4.4/gcc/Warning-Options.html). It stills compiling well without any additional errors. – BloodyMary Nov 18 '18 at 14:22
  • 2
    GCC 3.4 is in 2018 an ancient obsolete version. Try with [GCC 8](https://gcc.gnu.org/gcc-8/) using `gcc -Wall -Wextra -g` and read [*How to debug small programs*](https://ericlippert.com/2014/03/05/how-to-debug-small-programs/) – Basile Starynkevitch Nov 18 '18 at 14:30
  • @BasileStarynkevitch Thanks. Now I managed to reproduce the warning with my code and now I can see it. Huge thanks. For now on I will use only new gcc. – BloodyMary Nov 18 '18 at 14:35

2 Answers2

2

As astat is not yet initialize/assign before astat->st_uid, code exhibir undeifed behavior (UB). In OP case, the code crashed,

Instead of declaring a pointer with no value, code nneds to:

1) Declare a struct stat object.

2) Populated it with a *stat() call. ref.

int main(int argc, char *argv[]) {
  DIR *katalog;
  struct dirent *dir;
  katalog = opendir(".");

  //struct stat *astat;

  if (argc == 1) {
    printf("Without option");
    if (katalog) {
      while ((dir = readdir(katalog)) != NULL) {
        // add
        struct stat sb;
        if (lstat(dir->d_name, &sb) == -1) {
          perror("lstat");
          exit(EXIT_FAILURE);
        }
        if (sb.st_uid != 0) {
          printf("%s %llu \n", dir->d_name, (unsigned long long) sb.st_uid);
        }
      }
      closedir(katalog);
    }
  }
  return (0);
}
chux - Reinstate Monica
  • 143,097
  • 13
  • 135
  • 256
  • I would suggest a `memset(&sb, 0, sizeof(sb));` before the line doing `lstat` – Basile Starynkevitch Nov 18 '18 at 14:28
  • OK. Now it works, but it's too way complited than my initial code. I need to check it line by line to understand everything, and to implement a solution for all stats in my own code. Thank you for your time and for all your comments. I really appreciate it. – BloodyMary Nov 18 '18 at 14:31
  • @BloodyMary BTW: Good used of `%llu` and `(unsigned long long)` to print `sb.st_uid`. Who or what text suggested that? – chux - Reinstate Monica Nov 18 '18 at 14:43
  • @chux Firstly I used of course other, wrong format, which gives me an error. Then I read this: https://stackoverflow.com/questions/15166410/c-format-issue-with-printfd-astatbuff-st-size. – BloodyMary Nov 18 '18 at 15:52
1

astat is not initialized in your code (use in you while loop)

OznOg
  • 4,440
  • 2
  • 26
  • 35
  • Hi! Thanks for an answer. Can you elaborate on that? I just started to learn C yesterday. I thought that "struct stat *astat;" is enough to initialize my variable. The error occurs also when I'm trying to set the "astat = 0" at the beginning of the code. – BloodyMary Nov 18 '18 at 13:53
  • @BloodyMary What value did you expect the pointer `astat` to have with `struct stat *astat;`? – chux - Reinstate Monica Nov 18 '18 at 13:57
  • @chux I expected that it would take any value included in stat structure (as shown here http://man7.org/linux/man-pages/man2/stat.2.html), depending on to which field I will reference in my code -> in this example I'm referencing to st_uid using astat->st_uid. It works for directories names (first code that I gave), so I thought it will also work for user ids (st_uid) and it will show me all files with the code above + st_uids for all of them. – BloodyMary Nov 18 '18 at 14:03
  • @BloodyMary Pretend code after `struct stat *astat;` did not exist. What value did you expect the pointer `astat` to have after the line of code `struct stat *astat;`? It is _uninitialized_. So when code gets to `astat->st_uid`, `astat` is an uninitialized value. Calling `readdir(katalog)` does not affect `astat`. Code is missing a `*stat()` call amongst other things. – chux - Reinstate Monica Nov 18 '18 at 14:06
  • @chux I still don't get it. OK, I will try to follow the code on the man7.org that we linked to few comments above. C is so unlogic for me, nothing works as I expect... Python and MATLAB are so simple comparing to C... – BloodyMary Nov 18 '18 at 14:25
  • I don't really know what to elaborate; if you don't understand really how pointers are working, giving you more context on stat won't help IMHO. Probably you should try to learn with simple examples; I don't think that stat() is a good place to learn C.... – OznOg Nov 18 '18 at 16:01