Logo  

CS456 - Systems Programming

Displaying exercises/e1/solution/ls.c

#include <stdio.h>
#include <dirent.h>
#include <stdlib.h>
#include <string.h>
#include <pwd.h>
#include <grp.h>
#include <sys/stat.h>
#include <sys/types.h>

int filter(const struct dirent *ent)
{
  if (strcmp(ent->d_name, ".") == 0 || strcmp(ent->d_name, "..") == 0) return 0;
  return 1;
}

void filetype(mode_t mode)
{
  switch(mode & S_IFMT) {
    case S_IFSOCK: putchar('s'); break;
    case S_IFLNK: putchar('l'); break;
    case S_IFREG: putchar('-'); break;
    case S_IFBLK: putchar('b'); break;
    case S_IFDIR: putchar('d'); break;
    case S_IFCHR: putchar('c'); break;
    case S_IFIFO: putchar('p'); break;
    default: putchar('?'); break;
  }
}

void perms(mode_t mode)
{
  char *s = "tssTSS";

  int special = (mode & (7 << 9)) >> 9;
  for(int i=2; i >=0 ; i--) {
    int mask = 7 << (3*i);
    int perms = (mode & mask) >> (3*i);
    putchar(perms & 4? 'r' : '-');
    putchar(perms & 2? 'w' : '-');
    if (special & (1<<i)) {
      putchar(perms & 1? s[i] : s[i+3]);
    } else {
      putchar(perms & 1? 'x' : '-');
    }
  }
}

char *username(uid_t uid)
{
  static char uidbuf[32];
  struct passwd *pwd = getpwuid(uid);
  if (pwd == NULL) {
    sprintf(uidbuf, "%d", uid);
    return uidbuf;
  }
  return pwd->pw_name;
}

char *group(gid_t gid)
{
  static char gidbuf[32];
  struct group *grp = getgrgid(gid);
  if (grp == NULL) {
    sprintf(gidbuf, "%d", gid);
    return gidbuf;
  }
  return grp->gr_name;
}


int main(int argc, char *argv[])
{
  char path[PATH_MAX];
  struct dirent **namelist;
  int n;
  char *dir = ".";
  struct stat st;

  if (argc >= 2) dir = argv[1];

  n = scandir(dir, &namelist, filter, alphasort);
  if (n == -1) {
      perror("scandir");
      return 1;
  }

  for(int i = 0; i < n; i++) {
    sprintf(path, "%s/%s", dir, namelist[i]->d_name);
    if (stat(path, &st) < 0) {
      perror("stat");
      continue;
    }
    filetype(st.st_mode);
    perms(st.st_mode);
    printf("%4d %s %s %8d %s\n",
	   st.st_nlink, username(st.st_uid), group(st.st_gid),
	   st.st_size, namelist[i]->d_name);
    // Now you can use 'path' to stat the file at it's real location.
    free(namelist[i]);
  }
  free(namelist);

  return 0;
}