0

I am running a C program in linux, which prints filename plus its user and group ownership. I am using getpwuid and getgrgid.

When file is owned by non-existent user (ie, there is no entry in /etc/passwd for given UID on my machine), my program segfaults with "terminated by signal 11".

How can I make my program behave same as ls, so that it prints numerical UID when user does not exist, instead of segfaulting?

Relevant code snippet is below:

lstat(filename,&fileStat)

struct group *grp;
struct passwd *pwd;

pwd = getpwuid(fileStat.st_uid);
printf(" %s", pwd->pw_name);

grp = getgrgid(fileStat.st_gid);
printf(" %s", grp->gr_name);
Martin Vegter
  • 136
  • 9
  • 32
  • 56
  • 2
    check if pwd is not NULL before accessing it's value. And if the value is NULL you use the uid from lstat as the name – Seek Addo Apr 02 '17 at 20:24

2 Answers2

2

getpwuid and getgrgid return a NULL pointer if the user is not found in /etc/passwd database or there was an error. You have to check that is not NULL before accessing it value to avoid segfaults.

You have to also check the return value of lstat to be sure that it was successful before using fileStat otherwise it cause another segfault. lstat returns -1 on fail and sets errno otherwise 0. lstat(3)

int ret =  lstat(filename,&fileStat)

if(ret == -1){
  fprintf(stderr, "lstat: (%s): %s\n", filename, strerror(errno));
  return 1;
}

struct group *grp;
struct passwd *pwd;

pwd = getpwuid(fileStat.st_uid);

if(pwd != NULL){
   printf(" %s", pwd->pw_name);
}else{
  printf(" %ld", (long)fileStat.st_uid);
}

grp = getgrgid(fileStat.st_gid);
if(grp != NULL){
 printf(" %s", grp->gr_name);}
else{
  printf(" %ld", (long)fileStat.st_gid);
}

getpwuid(3) Sometimes it might return a NULL pointer on an error and will set errno. Which you have to set errno to zero before you check for the specific error

Seek Addo
  • 1,871
  • 2
  • 18
  • 30
1

Looking at the man page GETPWUID(3P)

RETURN VALUE

The getpwuid() function shall return a pointer to a struct passwd with the structure as defined in with a matching entry if found. A null pointer shall be returned if the requested entry is not found, or an error occurs. On error, errno shall be set to indicate the error.

Check for a null pointer before accessing anything, e.g.

pwd = getpwuid(fileStat.st_uid);
if (pwd) {
    printf(" %s", pwd->pw_name);
} else {
    // handle non-existing user entry
}
Olaf Dietsche
  • 72,253
  • 8
  • 102
  • 198