I'm working on a c programming mimicking UNIX shell and I wonder if there's a way to find an executable file(command file) in a specific directory
Asked
Active
Viewed 687 times
1 Answers
3
By executable file, I am assuming you are looking for any file that is not a directory that has the execution flag set.
One way you could go about achieving your goal is to:
- Get a directory stream corresponding to the directory by using the opendir.
- Iterate through the directory stream using readdir .
- At each iteration, find the absolute path of the file, which can be computed by concatenating the directory path and file name (can be obtained by accessing the d_name of the
dirent
struct), pass this path to stat, and use bit mask specified in inode documentation to check for the execution permission.
Code:
#include <stdio.h>
#include <sys/types.h> //opendir, stat
#include <dirent.h> //opendir
#include <errno.h>
#include <string.h>
#include <sys/stat.h> //stat
#include <stdlib.h> //free, malloc
int main(int argc, char** argv) {
if (argc < 2) {
fprintf(stderr, "Usage: ./a.out path_to_a_directory \n");
return 1;
}
char* path_to_directory = argv[1];
int path_length = strlen(path_to_directory);
int modified = 0;
//Modify path so that a dash is at the end.
if (path_to_directory[path_length - 1] != '/') {
char* modified_path = (char *) malloc(sizeof(char) * (strlen(path_to_directory) + 2));
//Copies the null character as well.
strcpy(modified_path, path_to_directory);
modified_path[path_length] = '/';
modified_path[path_length + 1] = '\0';
path_to_directory = modified_path;
//Set flag to true so that the dynamically allocated memory is freed later.
modified = 1;
}
//Get the directory stream corresponding to the directory.
DIR* in_directory_stream = opendir(path_to_directory);
if (in_directory_stream == NULL) {
fprintf(stderr, "Error: the specified directory cannot be found or opened. \n", errno);
if (modified) free(path_to_directory);
return 1;
}
dirent* entry = NULL;
printf("Files that are executable by at least one of the permission classes (owner, group, others) are: \n");
while ((entry = readdir(in_directory_stream)) != NULL) {
//All directories contain . and .., which corresponds to current and parent directory respectively,
//in unix systems. Since we are looking for only executable files, we can ignore them.
if (!strcmp(".", entry->d_name)) {
continue;
}
if (!strcmp("..", entry->d_name)) {
continue;
}
//Get file information.
struct stat entry_info;
/* Create the absolute path of the entry.
* Without it, as mentioned by Shawn below,
* stat will look for a file with the entry's name in current working directory
* instead of the specified directory.
*/
char* entry_absolute_path = (char *) malloc(sizeof(char) * (strlen(path_to_directory)
+ strlen(entry->d_name) + 1));
strcat(entry_absolute_path, path_to_directory);
strcat(entry_absolute_path, entry->d_name);
if (stat(entry_absolute_path, &entry_info) == -1) {
fprintf(stderr, "Error in obtaining file information about %s\n", entry->d_name);
} else {
// Check if the file is not a directory and
// is executable by one of the permission classes (owner, group, others).
if (((entry_info.st_mode & S_IFMT) != S_IFDIR) &&
((entry_info.st_mode & S_IXUSR) || (entry_info.st_mode & S_IXGRP)
|| (entry_info.st_mode & S_IXOTH))) {
printf("%s\n", entry->d_name);
}
}
free(entry_absolute_path);
}
//Close directory stream.
closedir(in_directory_stream);
if (modified) free(path_to_directory);
return 0;
}
EDIT: Corrected the program to pass the absolute path of the file to stat
. Prior to this edit, the stat was given only the file name resulting in the program searching only the current working directory. Error identified by Shawn
-
Gotta take into account the filename in the `dirent` struct doesn't include directory. Need that too for `stat()`. – Shawn Jun 03 '21 at 23:10
-
What do you mean by the "file name in the `dirent` struct doesn't include directory "? My understanding is that if a directory contained a subdirectory, we would get a `dirent` struct corresponding to that subdirectory when we iterate through the directory stream. – David Jun 04 '21 at 00:50
-
1If you `opendir()` "/foo/bar/", the file names don't have `/foo/bar/` in front, so unless you're scanning your current working directory, `stat()` will fail unless a file with the same name just happens to be present in the cwd - and it'll be looking at the wrong file in that case. – Shawn Jun 04 '21 at 01:25
-
See [this question and answers](https://stackoverflow.com/questions/5125919/stat-error-no-such-file-or-directory-when-file-name-is-returned-by-readdir) for more information. – Shawn Jun 04 '21 at 02:02
-
Thank you for identifying that error. I have corrected the program above. – David Jun 04 '21 at 03:02