#include <sys/types.h>
#include <sys/stat.h>
#include <dirent.h>
#include <stdio.h>
#include <errno.h>
#include <string.h>
#include <unistd.h>

int main(int argc, char *argv[]) 
{
	char		directory[_POSIX_PATH_MAX+1];
	char		dirbuf[_POSIX_PATH_MAX+1];
	char		commastr[] = ", ";
	char		nirwanastr[] = " (going to nirwana :-)), ";
	char		*cstr = commastr;
	char		*dirptr = NULL;
	DIR 		*dir = NULL;
	struct dirent 	*direntry = NULL; 
	struct stat	statbuf;
	int		retval = 0;
	int		exectest = 0;
	uid_t		myuid  = getuid();
	uid_t           myeuid = geteuid();
	uid_t		mygid  = getgid();
	uid_t           myegid = getegid();


	if (argc != 2) {
		fprintf(stderr, "usage: program <path>\n");
		return 1;
	}

	strcpy(directory, argv[1]);
	strcpy(dirbuf, directory);
	if (dirbuf[(retval=strlen(dirbuf) == 0) ? 0 : retval - 1] != '/') {
		strcat(dirbuf, "/");
		dirptr = &dirbuf[strlen(dirbuf)];
	}

	if ((retval = stat(directory, &statbuf)) < 0) {
		fprintf(stderr, "stat(%s) errno was: %d\n", 
				directory, errno);
		return errno;
	} else {
	    if ((retval = lstat(directory, &statbuf)) < 0) {
		fprintf(stderr, "lstat(%s) errno was: %d\n", 
				directory, errno);
		return errno;
	    }
	}

	if (S_ISDIR(statbuf.st_mode) == 0) {
		fprintf(stderr, "\"%s\" is not a directory\n", 
				directory);
		return errno;
	}
        if (myeuid == statbuf.st_uid) {
	  if ((statbuf.st_mode & (S_IXUSR|S_IRUSR)) !=  (S_IXUSR|S_IRUSR)) {
		fprintf(stderr, "can not read or change into directory %s %x,%x\n", 
				directory);
		return errno;
	  }
	} else {
	  if ((statbuf.st_mode & (S_IXOTH|S_IROTH)) !=  (S_IXOTH|S_IROTH)) {
		fprintf(stderr, "can not read or change into directory %s\n", 
				directory);
		return errno;
	  }
	}


	if ((dir = opendir(directory)) == NULL) {
		fprintf(stderr, "opendir(%s) errno was: %d\n", 
				directory, errno);
		return errno;
	}

	
	while ((direntry = readdir(dir)) != NULL) {
	  exectest=0;
	  cstr = commastr;
	  fprintf(stdout, 
		"dir: strlen(%d), \td_name(%s) \t",
		strlen(direntry->d_name),
		direntry->d_name);

	  strcpy(dirptr, direntry->d_name);

	  /* 
	   * the big file test ;-))))
	   *
	   * test with stat() if directory entry exists
	   *   OK,     retest with lstat() if it is really a link
	   *   NOT OK, retest with lstat() if is a link to nirwana
	   */
	  if ((retval = stat(dirbuf, &statbuf)) < 0) {
	  	cstr = nirwanastr;
	        if ((retval = lstat(dirbuf, &statbuf)) < 0) {
		  fprintf(stderr, "stat(%s) errno was: %d\n", 
				directory, errno);
		  continue;
	        }
	  } else {
	    if ((retval = lstat(dirbuf, &statbuf)) < 0) {
		fprintf(stderr, "lstat(%s) errno was: %d\n", 
				directory, errno);
		continue;
	    }
	  }

	  fprintf(stdout, "(m:%o,i:%d) ", statbuf.st_mode, statbuf.st_ino);

	  if (S_ISLNK(statbuf.st_mode)) {
	    fprintf(stdout, "is it a symbolic link%s", cstr);
	    exectest=1;
	  }

	  if (S_ISREG(statbuf.st_mode)) {
	    fprintf(stdout, "regular file%s", cstr);
	    exectest=1;
	  }

	  if (S_ISDIR(statbuf.st_mode)) {
	    fprintf(stdout, "directory%s", cstr);
	    exectest=0;
	  }
	  if (S_ISCHR(statbuf.st_mode)) {
	    fprintf(stdout, "character device%s", cstr);
	    exectest=0;
	  }
	  if (S_ISBLK(statbuf.st_mode)) {
	    fprintf(stdout, "block device%s", cstr);
	    exectest=0;
	  }
	  if (S_ISFIFO(statbuf.st_mode)) {
	    fprintf(stdout, "fifo%s", cstr);
	    exectest=0;
	  }
	  if (S_ISSOCK(statbuf.st_mode)) {
	    fprintf(stdout, "socket%s", cstr);
	    exectest=0;
	  }

	  if (exectest) {
	    mode_t mask;
	    char s = 0;
            if (myeuid == statbuf.st_uid) {
		    mask = S_IRWXU;
		    fprintf(stdout, "u");
		    s = 0;
	    } else if (myegid == statbuf.st_gid) {
		    mask = S_IRWXG;
		    fprintf(stdout, "g");
		    s = 1;
	    } else {
		    mask = S_IRWXO;
		    fprintf(stdout, "o");
		    s = 2;
	    }

	    switch ((statbuf.st_mode & mask) >> s) {
		    case S_IRUSR|S_IWUSR|S_IXUSR:
			fprintf(stdout, "rwx");
			break;
		    case S_IRUSR|S_IWUSR:
			fprintf(stdout, "rw-");
			break;
		    case S_IRUSR|S_IXUSR:
			fprintf(stdout, "r-x");
			break;
		    case S_IWUSR|S_IXUSR:
			fprintf(stdout, "-wx");
			break;
		    case S_IRUSR:
			fprintf(stdout, "r--");
			break;
		    case S_IWUSR:
			fprintf(stdout, "-w-");
			break;
		    case S_IXUSR:
			fprintf(stdout, "--x");
			break;
		    default:
			fprintf(stdout, "---");
			break;
	    }
	  }
	  fprintf(stdout, "\n");
		
	}

	closedir(dir);
	return 0;
}
