#include <sys/types.h>
#include <sys/stat.h>
#include <sys/sysmacros.h>
#include <ctype.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>
#include <unistd.h>
/*
* should be defined in header files but . . .
*/
#define S_ISSOCK(x) ((x)&014)
ssize_t readlink(const char *, char *, size_t);
int lstat(const char *, struct stat *);
/*
* printing permissions
*/
/* how many bits to shift left to get the set needed */
#define PRIV 9 /* privilege bits */
#define USER 6 /* permissions for UID */
#define GROUP 3 /* permissions for GID */
#define OTHER 0 /* permissions for everyone else */
char *p_rights[] = { "setuid", "setgid", "sticky" };
char *f_rights[] = { "read", "write", "execute" };
char *d_rights[] = { "list", "modify", "search" };
char perm_buf[128]; /* big enough to hold response */
/*
* print permissions in a readable fashion
* note what we print depends on the file type
*/
char *perm(int what, mode_t f_perms)
{
char **rights;
unsigned short bits;
if (S_ISDIR(f_perms))
rights = d_rights;
else
rights = f_rights;
switch(what){
case USER: case GROUP: case OTHER:
bits = (f_perms>>what)&07;
break;
default:
return("*** internal error ***");
}
perm_buf[0] = '\0';
switch(bits){
case 7: /* read, write, and execute */
(void) strcpy(perm_buf, rights[0]);
(void) strcat(perm_buf, ", ");
(void) strcat(perm_buf, rights[1]);
(void) strcat(perm_buf, ", and ");
(void) strcat(perm_buf, rights[2]);
break;
case 6: /* read and write */
(void) strcpy(perm_buf, rights[0]);
(void) strcat(perm_buf, " and ");
(void) strcat(perm_buf, rights[1]);
break;
case 5: /* read and execute */
(void) strcpy(perm_buf, rights[0]);
(void) strcat(perm_buf, " and ");
(void) strcat(perm_buf, rights[2]);
break;
case 4: /* read */
(void) strcpy(perm_buf, rights[0]);
break;
case 3: /* write and execute */
(void) strcpy(perm_buf, rights[1]);
(void) strcat(perm_buf, " and ");
(void) strcat(perm_buf, rights[2]);
break;
case 2: /* write */
(void) strcpy(perm_buf, rights[1]);
break;
case 1: /* execute */
(void) strcpy(perm_buf, rights[2]);
break;
case 0: /* execute */
(void) strcpy(perm_buf, "do nothing");
break;
default:
(void) strcpy(perm_buf, "*** internal error ***");
break;
}
return(perm_buf);
}
/*
* print privileges
*/
char *priv(mode_t p_perms)
{
unsigned short bits;
bits = (p_perms>>PRIV)&07;
perm_buf[0] = '\0';
switch(bits){
case 7: /* setuid, setgid, and sticky */
(void) strcpy(perm_buf, p_rights[0]);
(void) strcat(perm_buf, ", ");
(void) strcat(perm_buf, p_rights[1]);
(void) strcat(perm_buf, ", and ");
(void) strcat(perm_buf, p_rights[2]);
break;
case 6: /* setuid and setgid */
(void) strcpy(perm_buf, p_rights[0]);
(void) strcat(perm_buf, " and ");
(void) strcat(perm_buf, p_rights[1]);
break;
case 5: /* setuid and sticky */
(void) strcpy(perm_buf, p_rights[0]);
(void) strcat(perm_buf, " and ");
(void) strcat(perm_buf, p_rights[2]);
break;
case 4: /* setuid */
(void) strcpy(perm_buf, p_rights[0]);
break;
case 3: /* setgid and sticky */
(void) strcpy(perm_buf, p_rights[1]);
(void) strcat(perm_buf, " and ");
(void) strcat(perm_buf, p_rights[2]);
break;
case 2: /* setgid */
(void) strcpy(perm_buf, p_rights[1]);
break;
case 1: /* sticky */
(void) strcpy(perm_buf, p_rights[2]);
break;
case 0:
(void) strcpy(perm_buf, "none");
break;
default:
(void) strcpy(perm_buf, "*** internal error ***");
break;
}
return(perm_buf);
}
/*
* this prints the file type
*/
char *ftype(mode_t f_perms)
{
if (S_ISREG(f_perms)) return("regular file");
else if (S_ISDIR(f_perms)) return("directory");
else if (S_ISCHR(f_perms)) return("character special device");
else if (S_ISBLK(f_perms)) return("block special device");
else if (S_ISFIFO(f_perms)) return("fifo (named pipe)");
else if (S_ISLNK(f_perms)) return("symbolic link");
else if (S_ISSOCK(f_perms)) return("socket");
/* should never get here, but just in case . . . */
sprintf(perm_buf, "*** unknown type (%0o) ***", (f_perms>>12)&0xf);
return(perm_buf);
}
/*
* print time
*/
char p_time[1024];
char *timefmt = "%A, %B %e, %Y at %l:%M:%S%p %Z";
char *prtime(time_t tock)
{
struct tm ticktock;
ticktock = *localtime(&tock);
if (!strftime(p_time, sizeof(p_time), timefmt, &ticktock))
sprintf(p_time, "%ld", tock);
return(p_time);
}
int do_stat(char *);
int main(int argc, char *argv[])
{
int i;
/*
* need at least one file name
*/
if (argc == 1){
fprintf(stderr, "Usage: %s file1 [ ... ]\n", argv[0]);
(void) exit(1);
}
/*
* do the files one at a time
*/
for(i = 1; i < argc; i++){
if (do_stat(argv[i]) && i+1 != argc)
printf("====================\n");
}
/*
* all done!
*/
(void) exit(0);
}
/*
* do the file
*/
int do_stat(char *fname)
{
struct stat stbuf;
char *lname;
ssize_t r;
/*
* get the file information and complain on error
*/
if (lstat(fname, &stbuf) < 0){
perror(fname);
return(0);
}
/*
* print file name
*/
printf("%s:\n", fname);
/*
* print file system information
*/
printf("\t* File system information:\n");
printf("\t Major ID of file's device: %d\n", (int) major(stbuf.st_dev));
printf("\t Minor ID of file's device: %d\n", (int) minor(stbuf.st_dev));
printf("\t Optimal file system blocksize: %ld\n", (long) stbuf.st_blksize);
printf("\t File inode number %ld\n", (long) stbuf.st_ino);
if (S_ISBLK(stbuf.st_mode) || S_ISCHR(stbuf.st_mode)){
printf("\t File is a device interface:\n");
printf("\t\tMajor device number (driver number): %d\n", (int) major(stbuf.st_rdev));
printf("\t\tMinor device number (driver dependent): %d\n", (int) minor(stbuf.st_rdev));
}
/*
* print file type, and target if a symlink
*/
printf("\t* File type information:\n");
printf("\t File type: %s", ftype(stbuf.st_mode));
if (S_ISLNK(stbuf.st_mode)){
printf(" [");
if ((lname = malloc(stbuf.st_size+1)) == NULL)
printf("*** Ran out of memory ***");
else if ((r = readlink(fname, lname, stbuf.st_size + 1)) < 0)
printf("*** Error reading link name ***");
else if (r > stbuf.st_size)
printf("*** Contents changed during read ***");
else{
lname[stbuf.st_size] = '\0';
printf("%s", lname);
}
printf("]");
}
putchar('\n');
printf("\t Number of hard links: %ld\n", (long) stbuf.st_nlink);
printf("\t Number of bytes in file: %ld\n", (long) stbuf.st_size);
printf("\t Number of 512 byte blocks allocated: %ld\n", (long) stbuf.st_blocks);
/*
* print file permission and ownership information
*/
printf("\t* File permission information:\n");
printf("\t User ID: %d\n", (int) stbuf.st_uid);
printf("\t Group ID: %d\n", (int) stbuf.st_gid);
printf("\t Permissions: %04o\n", (int) (stbuf.st_mode&07777));
printf("\t\tUser can %s\n", perm(USER, stbuf.st_mode));
printf("\t\tGroup can %s\n", perm(GROUP, stbuf.st_mode));
printf("\t\tEveryone else can %s\n", perm(OTHER, stbuf.st_mode));
printf("\t* File privileges: %s\n", priv(stbuf.st_mode));
/*
* file times
*/
printf("\t* File time information:\n");
printf("\t Time of last access: %s\n", prtime(stbuf.st_atime));
printf("\t Time of last modification: %s\n", prtime(stbuf.st_mtime));
printf("\t Time of inode creation: %s\n", prtime(stbuf.st_ctime));
return(1);
}
|
ECS 36A, Programming & Problem Solving Version of April 2, 2024 at 12:13PM
|
You can get the raw source code here. |