Skip to content

Instantly share code, notes, and snippets.

@zhanghai
Last active January 15, 2017 11:30
Show Gist options
  • Save zhanghai/5c71c41914ef153d621b to your computer and use it in GitHub Desktop.
Save zhanghai/5c71c41914ef153d621b to your computer and use it in GitHub Desktop.
A simple 'ls' program that mimics the behavior of `ls -ali`
/*
* A simple 'ls' program that mimics the behavior of `ls -ali`
* Copyright (C) 2014 Zhang Hai.
*
* This program is free software: you can redistribute it and/or
* modify it under the terms of the GNU General Public License as
* published by the Free Software Foundation, either version 3 of the
* License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see
* <http://www.gnu.org/licenses/>.
*/
#include <dirent.h>
#include <errno.h>
#include <pwd.h>
#include <grp.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <time.h>
#include <unistd.h>
int main(int argc, char *argv[]) {
time_t recent;
char *dirname;
DIR *dir;
struct dirent *dirent;
char *absname;
struct stat fstat;
char mode[11];
struct passwd *pwd;
struct group *grp;
char *timefmt, mtime[256];
errno = 0;
time(&recent);
/* From GNU coreutils ls implementation:
Consider a time to be recent if it is within the past six
months. A Gregorian year has 365.2425 * 24 * 60 * 60 ==
31556952 seconds on the average. Write this value as an
integer constant to avoid floating point hassles. */
recent -= 31556952 / 2;
if (argc == 1) {
dirname = ".";
} else if (argc == 2) {
dirname = argv[1];
} else {
printf("Usage: ls [directory]\n");
return -1;
}
dir = opendir(dirname);
if (errno) {
perror("opendir");
return errno;
}
while ((dirent = readdir(dir)) != NULL) {
absname = malloc(strlen(dirname) + strlen(dirent->d_name)
+ 2);
strcpy(absname, dirname);
strcat(absname, "/");
strcat(absname, dirent->d_name);
stat(absname, &fstat);
if (errno) {
perror("stat");
free(absname);
continue;
}
free(absname);
if (S_ISREG(fstat.st_mode)) { mode[0] = '-'; }
else if (S_ISBLK(fstat.st_mode)) { mode[0] = 'b'; }
else if (S_ISCHR(fstat.st_mode)) { mode[0] = 'c'; }
else if (S_ISDIR(fstat.st_mode)) { mode[0] = 'd'; }
else if (S_ISLNK(fstat.st_mode)) { mode[0] = 'l'; }
else if (S_ISFIFO(fstat.st_mode)) { mode[0] = 'p'; }
else if (S_ISSOCK(fstat.st_mode)) { mode[0] = 's'; }
mode[1] = fstat.st_mode & S_IRUSR ? 'r' : '-';
mode[2] = fstat.st_mode & S_IWUSR ? 'w' : '-';
mode[3] = fstat.st_mode & S_IXUSR ? 'x' : '-';
mode[4] = fstat.st_mode & S_IRGRP ? 'r' : '-';
mode[5] = fstat.st_mode & S_IWGRP ? 'w' : '-';
mode[6] = fstat.st_mode & S_IXGRP ? 'x' : '-';
mode[7] = fstat.st_mode & S_IROTH ? 'r' : '-';
mode[8] = fstat.st_mode & S_IWOTH ? 'w' : '-';
mode[9] = fstat.st_mode & S_IXOTH ? 'x' : '-';
mode[10] = 0;
pwd = getpwuid(fstat.st_uid);
if (errno) {
perror("getpwuid");
continue;
}
grp = getgrgid(fstat.st_gid);
if (errno) {
perror("getgrgid");
continue;
}
timefmt = fstat.st_mtim.tv_sec > recent ? "%b %d %H:%M"
: "%b %d %Y";
strftime(mtime, sizeof(mtime), timefmt,
localtime(&fstat.st_mtim.tv_sec));
printf("%lu %s %lu %s %s %ld %s %s\n",
fstat.st_ino, mode, fstat.st_nlink, pwd->pw_name,
grp->gr_name, fstat.st_size, mtime, dirent->d_name);
}
if (errno) {
perror("readdir");
}
closedir(dir);
if (errno) {
perror("closedir");
}
return errno;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment