diff options
Diffstat (limited to 'src/sash/cmd_file.c')
-rw-r--r-- | src/sash/cmd_file.c | 235 |
1 files changed, 235 insertions, 0 deletions
diff --git a/src/sash/cmd_file.c b/src/sash/cmd_file.c new file mode 100644 index 0000000..caf2a30 --- /dev/null +++ b/src/sash/cmd_file.c @@ -0,0 +1,235 @@ +/* + * Copyright (c) 2014 by David I. Bell + * Permission is granted to use, distribute, or modify this source, + * provided that this copyright notice remains intact. + * + * The "file" built-in command. + */ + +#include <ctype.h> +#include <errno.h> +#include <sys/types.h> +#include <sys/stat.h> + +#include "sash.h" + + +static const char * checkFile(const char * name); + + +int +do_file(int argc, const char ** argv) +{ + const char * name; + const char * info; + + argc--; + argv++; + + while (argc-- > 0) + { + name = *argv++; + + info = checkFile(name); + + if (info == NULL) + info = "No information available"; + + printf("%s: %s\n", name, info); + } + + return 0; +} + + +/* + * Examine the specified file and return a static string which + * describes the file type. Returns NULL on a failure. + */ +static const char * +checkFile(const char * name) +{ + int mode; + int fd; + int cc; + int i; + int ch; + int badCount; + char * cp; + struct stat statBuf; + char data[8192]; + static char info[1024]; + + cp = info; + *cp = '\0'; + + if (lstat(name, &statBuf) < 0) + { + if (errno == ENOENT) + return "non-existent"; + + sprintf(cp, "stat failed: %s", strerror(errno)); + + return info; + } + + /* + * Check the file type. + */ + mode = statBuf.st_mode; + + if (S_ISDIR(mode)) + return "directory"; + + if (S_ISCHR(mode)) + return "character device"; + + if (S_ISBLK(mode)) + return "block device"; + + if (S_ISFIFO(mode)) + return "named pipe"; + +#ifdef S_ISLNK + if (S_ISLNK(mode)) + return "symbolic link"; +#endif + +#ifdef S_ISSOCK + if (S_ISSOCK(mode)) + return "socket"; +#endif + + /* + * If the file is not a regular file mention that. + */ + if (!S_ISREG(mode)) + { + sprintf(cp, "unknown mode 0x%x, \n", mode); + + cp += strlen(cp); + } + + /* + * Check for an executable file. + */ + if ((mode & (S_IEXEC | S_IXGRP | S_IXOTH)) != 0) + { + strcpy(cp, "executable, "); + + cp += strlen(cp); + } + + /* + * The file is a normal file. + * Open it if we can and read in the first block. + */ + fd = open(name, O_RDONLY); + + if (fd < 0) + { + sprintf(cp, "unreadable: %s", strerror(errno)); + + return info; + } + + cc = read(fd, data, sizeof(data)); + + if (cc < 0) + { + sprintf(cp, "read error: %s", strerror(errno)); + + (void) close(fd); + + return info; + } + + (void) close(fd); + + /* + * Check for an empty file. + */ + if (cc == 0) + { + strcpy(cp, "empty file"); + + return info; + } + + /* + * Check for a script file. + */ + if ((cc > 2) && (data[0] == '#') && (data[1] == '!')) + { + char * begin; + char * end; + + data[sizeof(data) - 1] = '\0'; + + begin = &data[2]; + + while (*begin == ' ') + begin++; + + end = begin; + + while (*end && (*end != ' ') && (*end != '\n')) + end++; + + *end = '\0'; + + sprintf(cp, "script for \"%s\"", begin); + + return info; + } + + /* + * Check for special binary data types. + */ + if ((data[0] == '\037') && (data[1] == '\235')) + return "compressed file"; + + if ((data[0] == '\037') && (data[1] == '\213')) + return "GZIP file"; + + if ((data[0] == '\177') && (memcmp(&data[1], "ELF", 3) == 0)) + { + strcpy(cp, "ELF program"); + + return info; + } + + /* + * Check for binary data. + */ + badCount = 0; + + for (i = 0; i < cc; i++) + { + ch = data[i]; + + if ((ch == '\n') || (ch == '\t')) + continue; + + if (isspace(ch) || isprint(ch)) + continue; + + badCount++; + } + + if (badCount != 0) + { + strcpy(cp, "binary"); + + return info; + } + + /* + * It is just a text file. + */ + strcpy(cp, "text file"); + + return info; +} + +/* END CODE */ |