I need to create a program that basically acts similarly to the list utility on Linux. I've been trying to get this to work and I'm pretty close but now I've gotten stuck. Essentially it will print whatever files and sub-directories that are contained withing a directory(i.e. if i run ./project3, it lists whatevers in that directory). However, once I try to get the recursive call working it spits out something like:
sh: 1: /home/RageKage/Documents/Project3/dir1: Permission denied
That's where I'm stuck, I'm not exactly sure what to do from here. I'm getting the path of the directory to explore using realpath and that works fine, but the recursive call just isn't working and I'm not exactly sure what I'm doing wrong. Any help would be appreciated as I'm relatively new to this.
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/types.h>
#include <dirent.h>
#include <string.h>
#include <limits.h>
int main (int argc, char *argv[])
{
DIR *dir;
struct dirent *sd;
const char *direct;
char buf[PATH_MAX + 1];
if (argc < 2)
{
direct = ".";
}else{
direct = argv[1];
//printf("Hey this is argv[1]: %s\n", argv[1]);
}
dir = opendir(direct);
if (dir == NULL)
{
printf("ERROR! NO DIRECTORY TO OPEN!\n");
exit(1);
}
while( (sd=readdir(dir)) != NULL )
{
if (!strcmp(sd->d_name, ".") || !strcmp(sd->d_name, ".."))
{
}else{
printf("\n>> %s\n", sd->d_name);
}
if (!strcmp(sd->d_name, "..") || !strcmp(sd->d_name, "."))
{
}else if (sd->d_type == 4){
printf("Attempting to Run!\n");
realpath(sd->d_name, buf);
printf("[%s]\n", buf);
system(("./project3 %s", buf));
printf("\n");
}
}
closedir(dir);
return 0;
}
system(("./project3 %s", buf));
Are you recursively calling the program itself again? That sounds a bit inefficient, and hard to do since you'd need to know where the executable file is. In general it could be just about anywhere (starting with /bin
, /usr/bin
etc.), and all you are likely to get in argv[0]
is the filename part, not the whole path.
Also, as said in the comments, func((this, that))
is the same as func(that)
, not func(this, that)
, since the parenthesis make the comma act as the comma operator, not as an argument separator. And system()
only takes one argument anyway, so you'd need to use sprintf()
to build the command line. (Or perhaps use the exec()
functions to actually give separate arguments without invoking a shell, but then you need to do the fork()
, too.)
I'd suggest scrapping that idea, and putting the directory tree walking into a function of it's own, and calling that recursively:
void walkpath(void)
{
DIR *dir = opendir(".");
struct dirent *sd;
while((sd = readdir(dir)) != NULL) {
/* ... */
if (sd->d_type == DT_DIR) {
chdir(sd->d_name);
walkpath();
chdir("..");
}
}
}
int main(...)
{
/* ... */
chdir(directory);
walkpath();
}
I used chdir
here to change the process's working directory along with the walk. If you need to track the full directory name, then you'll need to add that.
Also, now you have the test for .
and ..
twice. Use continue
to end that iteration of the loop so you don't need to test the same thing again.
if (strcmp(sd->d_name, ".") == 0 || strcmp(sd->d_name, "..") == 0) {
continue;
}