Code:
#include <stdio.h>
#include <sys/types.h>
#include <fcntl.h>
#include <dirent.h>
#include <stdlib.h>
#include <time.h>
#include <regex.h>
#include <errno.h>
#include <string.h>
#include <sys/stat.h>
#include <pwd.h>
#include <grp.h>
#include <unistd.h>
/*prototypes*/
char* workdir(void);
void printDetailsAll(char* filename,char* path);
void printDetails(char* filename);
int matchDetails(char* filename);
char *get_regerror(int errcode,regex_t *compiled);
int main(int argc, char **argv) {
int count,index,result;
char *curdir;
struct stat sbuf;
struct dirent **direntp;
char path[FILENAME_MAX];
if(argv[1] != '\0'){ /*If argument supplied*/
if(strcmp(argv[1], "-al") == 0){
if(argv[2] != '\0'){/*ls '-al' on an argument*/
if(stat(argv[2], &sbuf) != -1){
if(S_ISDIR(sbuf.st_mode)){ /* Is a directory */
count = scandir(argv[2],&direntp,NULL,alphasort);
if(count){
for(index=0; index<count; ++index){
strcpy(path,argv[1]);
printDetailsAll(direntp[index]->d_name,path);
free(direntp[index]);
}
}else{
fprintf(stderr,"Can't open %s\n",argv[1]);
exit(EXIT_FAILURE);
}
}else
printDetailsAll(argv[2],NULL);
}else
fprintf(stderr,"Can't stat %s\n", argv[1]);
}else{/*ls '-al' on curdir*/
curdir = workdir();
if(stat(curdir,&sbuf) !=-1){
count = scandir(curdir,&direntp,NULL,alphasort);
if(count){
for(index=0; index<count; ++index){
printDetailsAll(direntp[index]->d_name,NULL);
free(direntp[index]);
}
}else{
fprintf(stderr,"Can't open %s\n",curdir);
exit(EXIT_FAILURE);
}
}else{
fprintf(stderr,"Can't stat %s\n",curdir);
exit(EXIT_FAILURE);
}
free(curdir);
}
}else if(strcmp(argv[1], "-l") == 0){
if(argv[2] != '\0'){/*ls -l on an argument*/
if(stat(argv[2], &sbuf) != -1){
if(S_ISDIR(sbuf.st_mode)){ /* Is a directory */
count = scandir(argv[2],&direntp,NULL,alphasort);
if(count){
for(index=0; index<count; ++index){
strcpy(path,argv[1]);
result = matchDetails(direntp[index]->d_name);
if(result > 0)
printDetailsAll(direntp[index]->d_name,path);
free(direntp[index]);
}
}else{
fprintf(stderr,"Can't open %s\n",argv[1]);
exit(EXIT_FAILURE);
}
}else
printDetailsAll(argv[2],NULL);
}else
fprintf(stderr,"Can't stat %s\n", argv[1]);
}else{/*ls -l on current dir*/
curdir = workdir();
if(stat(curdir,&sbuf) !=-1){
count = scandir(curdir,&direntp,NULL,alphasort);
if(count){
for(index=0; index<count; ++index){
result = matchDetails(direntp[index]->d_name);
if(result > 0)
printDetailsAll(direntp[index]->d_name,NULL);
free(direntp[index]);
}
}else{
fprintf(stderr,"Can't open %s\n",curdir);
exit(EXIT_FAILURE);
}
}else{
fprintf(stderr,"Can't stat %s\n",curdir);
exit(EXIT_FAILURE);
}
free(curdir);
}
}else if(strcmp(argv[1], "-a") == 0){
if(argv[2] != '\0'){/*ls -a on an argument*/
if(stat(argv[2], &sbuf) != -1){
if(S_ISDIR(sbuf.st_mode)){ /* Is a directory */
count = scandir(argv[2],&direntp,NULL,alphasort);
if(count){
for(index=0; index<count; ++index){
printDetails(direntp[index]->d_name);
free(direntp[index]);
}
}else{
fprintf(stderr,"Can't open %s\n",argv[1]);
exit(EXIT_FAILURE);
}
}else
printDetails(argv[2]);
}else
fprintf(stderr,"Can't stat %s\n", argv[1]);
}else{
curdir = workdir();
if(stat(curdir,&sbuf) !=-1){
count = scandir(curdir,&direntp,NULL,alphasort);
if(count){
for(index=0; index<count; ++index){
printDetails(direntp[index]->d_name);
free(direntp[index]);
}
}else{
fprintf(stderr,"Can't open %s\n",curdir);
exit(EXIT_FAILURE);
}
}else{
fprintf(stderr,"Can't stat %s\n",curdir);
exit(EXIT_FAILURE);
}
free(curdir);
}
}
}else{ /*Normal ls command on curdir*/
curdir = workdir();
if(stat(curdir,&sbuf) !=-1){
count = scandir(curdir,&direntp,NULL,alphasort);
if(count){
for(index=0; index<count; ++index){
result = matchDetails(direntp[index]->d_name);
if(result > 0)
printDetails(direntp[index]->d_name);
free(direntp[index]);
}
}else{
fprintf(stderr,"Can't open %s\n",curdir);
exit(EXIT_FAILURE);
}
}else{
fprintf(stderr,"Can't stat %s\n",curdir);
exit(EXIT_FAILURE);
}
free(curdir);
}
return EXIT_SUCCESS;
}
/*Get the current working directory*/
char* workdir(){
while(1){
char* wdbuf = (char*)malloc(FILENAME_MAX);
if(getcwd(wdbuf,FILENAME_MAX) == wdbuf)
return wdbuf;
free(wdbuf);
if(errno != ERANGE){
fprintf(stderr,"Out of range\n");
return 0;
}
}
}
/*Will print all details of a file/dir. */
void printDetailsAll(char *filename,char *path){
struct passwd *my_passwd; /*User details*/
struct group *my_group; /*Group details*/
struct stat sbuf; /*File details*/
struct tm *strtime; /*Time format*/
int fdes; /*File descriptor*/
unsigned char type ='?'; /*File type*/
unsigned char usr[] = "---"; /*User Permissions*/
unsigned char grp[] = "---"; /*Group Permissions*/
unsigned char oth[] = "---"; /*Other Permissions*/
unsigned char uid[9], gid[9]; /*User name and Group name*/
unsigned char mod[13]; /*Time information*/
mode_t mode; /*Used to determine type and permission bits*/
char* curdir; /*Used to hold the current working directory*/
char* buf; /*Used to hold a link location*/
time_t now; /*Used to format the time*/
int year; /*Used to format the time*/
/*If path is null stat by the curdir*/
if(path == NULL){
curdir = workdir();
strcat(curdir,"/");
strcat(curdir,filename);
if(stat(curdir,&sbuf) != -1){
if(S_ISLNK(sbuf.st_mode)){
if(readlink(curdir,buf,(size_t)FILENAME_MAX) != -1){
if(lstat(buf,&sbuf) == -1){
fprintf(stderr,"Can't stat %s\n",filename);
return;
}
}else
fprintf(stderr,"Can't readlink %s\n",filename);
}else if(S_ISREG(sbuf.st_mode)){
if((fdes = open(curdir,O_RDONLY)) != ENOENT){
if(fstat(fdes,&sbuf) == -1){
fprintf(stderr,"Can't stat %s\n",filename);
return;
}
close(fdes);
}else{
fprintf(stderr,"Can't open %s\n",filename);
return;
}
}
}else{
fprintf(stderr,"Can't stat %s\n",filename);
return;
}
free(curdir);
/*Otherwise stat by the path provided*/
}else{
strcat(path,"/");
strcat(path,filename);
if(stat(path,&sbuf) != -1){
if(S_ISLNK(sbuf.st_mode)){
if(readlink(path,buf,(size_t)FILENAME_MAX) != -1){
if(lstat(buf,&sbuf) == -1){
fprintf(stderr,"Can't stat %s\n",filename);
return;
}
}else
fprintf(stderr,"Can't readlink %s\n",filename);
}else if(S_ISREG(sbuf.st_mode)){
if((fdes = open(path,O_RDONLY)) != ENOENT){
if(fstat(fdes,&sbuf) == -1){
fprintf(stderr,"Can't stat %s\n",filename);
return;
}
close(fdes);
}else{
fprintf(stderr,"Can't open %s\n",filename);
return;
}
}
}else{
fprintf(stderr,"Path: %s\n",path);
fprintf(stderr,"Can't stat %s\n",curdir);
return;
}
}
/*Get file types and permissions*/
mode = sbuf.st_mode;
if( S_ISLNK( mode ) ){ type = 'l'; /*symlink*/ printf("%c\n",type);}
else if( S_ISDIR ( mode ) ) type = 'd'; /*directory*/
else if( S_ISCHR ( mode ) ) type = 'c'; /*character raw device*/
else if( S_ISBLK ( mode ) ) type = 'b'; /*block raw device*/
else if( S_ISFIFO( mode ) ) type = 'p'; /*named pipe*/
else if( S_ISSOCK( mode ) ) type = 's'; /*Unix domain socket*/
else if( S_ISREG ( mode ) ) type = '-'; /*regular file*/
if( mode & S_IRUSR ) usr[0] = 'r';
if( mode & S_IWUSR ) usr[1] = 'w';
if( mode & S_IXUSR ) usr[2] = 'x';
if( mode & S_ISUID ) usr[2] = 's'; /* set UID bit*/
if( mode & S_IRGRP ) grp[0] = 'r';
if( mode & S_IWGRP ) grp[1] = 'w';
if( mode & S_IXGRP ) grp[2] = 'x';
if( mode & S_ISGID ) grp[2] = 's'; /* set GID bit*/
if( mode & S_IROTH ) oth[0] = 'r';
if( mode & S_IWOTH ) oth[1] = 'w';
if( mode & S_IXOTH ) oth[2] = 'x';
/*Get user information*/
my_passwd = getpwuid(sbuf.st_uid);
if(my_passwd != NULL){
strncpy(uid,my_passwd->pw_name,8);
uid[8] = '\0';
}else
snprintf(uid,9,"%d",sbuf.st_uid);
/*Get group information*/
my_group = getgrgid(sbuf.st_gid);
if(my_group != NULL){
strncpy(gid,my_group->gr_name,8);
gid[8] = '\0';
}else
snprintf(gid,9,"%d",sbuf.st_gid);
/*Format the time to readable form*/
time(&now);
year = localtime(&now)->tm_year;
strtime = localtime(&sbuf.st_ctime);
if(strtime->tm_year == year)
strftime(mod,13,"%b %e %R",strtime);
else
strftime(mod,13,"%b %e %Y",strtime);
/*print the details*/
printf("%c%s%s%-6s%-8d%-10s%-10s%-10d%-10s%s\n",
type,usr,grp,oth,sbuf.st_nlink,
uid,gid,sbuf.st_size,mod,filename);
}
/*Used to print the filename*/
void printDetails(char* filename){
printf("%s\n",filename);
}
/*Used to find process directories*/
int matchDetails(char* filename){
int status,regstat;
char *pattern = "^[^.].*$"; /*Match all strings without a begining '.'*/
char *result;
regex_t re;
if((regstat = regcomp(&re,pattern,REG_EXTENDED | REG_NOSUB)) != 0){
result = get_regerror(regstat,&re);
fprintf(stderr,"%s\n",result);
return(0);
}
if((status = regexec(&re,filename,(size_t) 0,NULL,0)) != 0)
return(0);
regfree(&re);
return(1);
}
/*Used to store regex errors*/
char *get_regerror(int errcode,regex_t *compiled){
size_t length = regerror(errcode,compiled,NULL,0);
char *buffer = malloc(length);
(void) regerror(errcode,compiled,buffer,length);
return buffer;
}