How to pass argument values in the program implementing the shell - c

SOURCE::
#include <stdio.h> // printf()
#include <stdlib.h> // exit()
#include <string.h> // string
#include <dirent.h> // microsoft base compiler. _chdir, _getcwd
#include <unistd.h> // unix base complier. getcwd, chdir
#include <fcntl.h>
#include <sys/types.h>
#include <sys/stat.h>
#define FILE_SIZE 1024
#define MAX 255
#define ERROR (-1)
void cmd_mkdir(int argc, char *argv);
void cmd_ls()
{
char * cwd = (char *)malloc(sizeof(char) * 1024);
DIR * dir = NULL;
struct dirent * entry = NULL;
getcwd(cwd, 1024);
if( (dir = opendir(cwd)) == NULL)
{
printf("current directory error\n");
exit(1);
}
while( (entry = readdir(dir)) != NULL)
{
printf("%s\n", entry->d_name);
}
free(cwd);
closedir(dir);
}
void cmd_pwd() {
char buf[MAX];
getcwd(buf, MAX);
printf("%s\n", buf);
}
int main(int argc, char *argv[])
{
char cBuf[MAX];
char *arg;
while(1) {
printf(">> ");
arg = fgets(cBuf, MAX, stdin);
if(argc < 2){
// printf("1111\n"); -- check
if(strncmp(arg, "ls", 2) == 0)
cmd_ls();
else if(strncmp(arg, "pwd", 3) == 0)
cmd_pwd();
else if(strncmp(arg, "exit", 4) == 0)
break;
} // if END
else {
// printf("2222\n"); -- check
if(strcmp(arg, "mkdir") == 0){
if (argc != 2)
fprintf(stderr, "Usage : jmkdir dirname\n");
if(mkdir(argv[1], 0755))
perror("mkdir error");
}
}// else END
} // while END
} // main END
Desired result::
How to get two input values (mkdir, mini_maked) as parameters after executing ./minishell (executable file implementing the shell)
$ ./minishell
>> mkdir mini_maked
Currently implemented ls, pwd, exit can be implemented because it can be used without options, but a command that requires a "command filename" such as mkdir is not implemented.
If the program itself functions as mkdir, it is solved using the values of argc and argv.
However, since the ./myshell program itself implements the shell program, when you run the program and receive mkdir mini_maked as an input, you are having a hard time executing the command.
If we get two inputs (mkdir, mini_maked) after program execution, how do we get these as parameters?

Related

How do I fix "copy: Bad file descriptor" in my C program

Hello I'm working on a program that prints all the characters like a cat program by using the POSIX functions, the program has to get more than one file when it does it writes the characters of all files in the destination file.
For example;
mycat.exe x.txt y.txt z.txt dest.txt
means write all the characters from x.txt, y.txt and z.txt in order to the file destination dest.txt that it's created after we run the program.
If any file not exits the program will not exit it prints a report that
file not exists
If any error occur, you have to exit the program.
When I compile it it compiles without any error(I'm compiling it in Windows 10), but when i try to run it it shows an error.
This is how I compile it:
gcc -o mycp.exe mycp.c
This is how i run it:
mycp.exe x.txt y.txt z.txt dest.txt
This is the error:
copy: Bad file descriptor
This is the code inside the mycp.c:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <errno.h>
#include <unistd.h>
#define BUFSIZE 1024
void exit_sys(const char* msg)
{
perror(msg);
exit(EXIT_FAILURE);
}
void exit_fail(const char* msg)
{
fprintf(stderr, "%s\n", msg);
exit(EXIT_FAILURE);
}
void remove_dest_file(int fd, char** argv, int i)
{
_close(fd);
unlink(argv[i]);
}
int copy_file(int fdd, int fds)
{
char buf[BUFSIZE];
int n;
while ((n = read(fds, buf, BUFSIZE)) > 0)
{
_write(fdd, buf, n);
}
if (n < 0)
{
return n;
}
return 0;
}
int main(int argc, char** argv)
{
int fds, fdd;
int n;
char buf[BUFSIZE];
int ch;
int flags;
int argcm1;
int i;
flags = _O_WRONLY | _O_CREAT;
if (argc < 2)
exit_fail("usage:mycp.exe file1.exe file2.exe file3.exe ... filen filedest.exe");
argcm1 = argc - 1;
if (!access(argv[argcm1], F_OK)) {
printf("The file %s exists. Do you want to overwrite?[y]\n", argv[argcm1]);
ch = getchar();
if (ch == 'y' || ch == 'Y')
flags |= _O_TRUNC;
else
exit(EXIT_SUCCESS);
}
if ((fdd = _open(argv[argcm1], flags, _S_IREAD | _S_IWRITE)) < 0)
{
exit_sys("open for destination");
}
for (i = 0; i < argcm1; ++i)
{
if (fds = _open(argv[i], _O_RDONLY) < 0)
{
remove_dest_file(fdd, argv, argcm1);
exit_sys("open");
}
if (copy_file(fds, fdd) < 0)
{
remove_dest_file(fdd, argv, argcm1);
exit_sys("copy");
}
_close(fds);
}
printf("Succes");
_close(fdd);
return 0;
}

Program opens the same named pipe and writes to it many times with C

I created two programs, which will communicate via named pipe, one will be reading from it and another one will be writing to it. It works pretty fine now, except for the fact, that it opens and writes to the same fifo exactly 3 times. It's my first time with C and pipes, and I don't understand why is this writing three times. Can you see why is this writing three times?
writing.c
#include <unistd.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <time.h>
#include <dirent.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <fcntl.h>
#define BUFFSIZE 512
#define err(mess) { fprintf(stderr,"Error: %s.", mess); exit(1); }
void writing(char *s)
{
int fd;
ssize_t n;
char buf[BUFFSIZE];
printf("writing to %s\n",s);
if ( (fd = open(s, O_WRONLY)) < 0)
err("open")
while( (n = read(STDIN_FILENO, buf, sizeof buf -1) ) > 0) {
buf[n-1] = '\0';
printf("Received: %s\n", buf);
if ( write(fd, buf, n) != n) {
err("write");
}
if(strcmp(buf,"END")==0){
printf("%s","exit");
break;
}
}
close(fd);
}
char* concat(const char *s1, const char *s2)
{
char *result = malloc(strlen(s1)+strlen(s2)+1);//+1 for the zero-terminator
strcpy(result, s1);
strcat(result, s2);
return result;
}
int file_stat(char *argv){
int isfifo = 0;
struct stat sb;
printf("%s",argv);
if (stat(argv, &sb) == -1) {
perror("stat");
exit(EXIT_FAILURE);
}
printf("File type: ");
if (sb.st_mode & S_IFMT == S_IFIFO) {
printf("FIFO/pipe\n");
isfifo = 1;
}
printf("Ownership: UID=%ld GID=%ld\n",
(long) sb.st_uid, (long) sb.st_gid);
//exit(EXIT_SUCCESS);
return isfifo;
}
int main(int argc, char *argv[])
{
// READ ALL FILES IN DIRECTORY
if (argc != 2) {
fprintf(stderr, "Usage: %s /<pathname>/\n", argv[0]);
exit(EXIT_FAILURE);
}
DIR *d;
struct dirent *dir;
if ((d = opendir (argv[1])) != NULL) {
/* print all the files and directories within directory */
while ((dir = readdir (d)) != NULL) {
printf ("%s\n", dir->d_name);
char* s = concat(argv[1], dir->d_name);
if (file_stat(s) == 1) {
writing(s);
}
else {
mkfifo("fifo_x", 0666);
writing("fifo_x");
}
free(s);
}
closedir (d);
}
else {
/* could not open directory */
perror ("error: ");
return EXIT_FAILURE;
}
}
reading file is the same except for "reading" function and call to reading()
reading
void reading(char *s)
{
int fd;
ssize_t n;
char buf[BUFFSIZE];
printf("%s",s);
if ( (fd = open(s, O_RDONLY)) < 0)
err("open");
while( (n = read(fd, buf, sizeof buf - 1) ) > 0) {
buf[n-1] = '\0';
if(strcmp(buf,"END")==0){
printf("%s\n", "exit");
break;
}
buf[n-1] = '\n';
if ( write(STDOUT_FILENO, buf, n) != n) {
exit(1);
}
}
close(fd);
}
the output
/home/..File type: Ownership: UID=0 GID=0
writing to fifo_x
END
Received: END
exitola
/home/olaFile type: Ownership: UID=1001 GID=1001
writing to fifo_x
END
Received: END
exit.
/home/.File type: Ownership: UID=0 GID=0
writing to fifo_x
END
Received: END
exit
You have three files in the directory with whose pathname you called your program. All three files are not fifo's so for each you write to fifo_x.
The file names are
.
..
olaFile
Maybe you should explicitly exclude the files
.
..
which happen to be in every directory in linux and represent the current directory . and the parent directory ...

Not sure why I am getting an undefine refence to gss_str_to_oid error

I am using gssapi in C for the first time. I am trying to reconstruct example on Oracle doc http://docs.oracle.com/cd/E19683-01/816-1331/sampleprogs-1/index.html.
In my .c file I call gss_str_to_oid(&min_stat, &tok, oid); and get an undefined reference error. I included #include "gssapi.h" at the top of my .c file. In gssapi.h there is a function call
OM_uint32 KRB5_CALLCONV
gss_str_to_oid(
OM_uint32 *, /* minor_status */
gss_buffer_t, /* oid_str */
gss_OID *);
So what am I doing wrong? I thought that if you included #include "gssapi.h" it would give me access to function in gssapi. Both files are in my src folder. So what am I doing wrong. I am using eclipse and from what in my makefile under targets it says all: GSS-API.
I am including most of my code below.
main
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <netdb.h>
#include <error.h>
#include <sys/stat.h>
#include <fcntl.h>
#include "gssapi.h"
#include "gssapi_ext.h"
#include "gss-misc.h"
/* global mech oid needed by display status, and acquire cred */
FILE *display_file;
gss_OID g_mechOid = GSS_C_NULL_OID;
void usage()
{
fprintf(stderr, "Usage: gss-client [-port port] [-d]"
" [-mech mechOid] host service msg\n");
exit(1);
}
static void parse_oid(char *mechanism, gss_OID *oid)
{
char *mechstr = 0, *cp;
gss_buffer_desc tok;
OM_uint32 maj_stat, min_stat;
if (isdigit(mechanism[0])) {
mechstr = malloc(strlen(mechanism)+5);
if (!mechstr) {
printf("Couldn't allocate mechanism scratch!\n");
return;
}
sprintf(mechstr, "{ %s }", mechanism);
for (cp = mechstr; *cp; cp++)
if (*cp == '.')
*cp = ' ';
tok.value = mechstr;
} else
tok.value = mechanism;
tok.length = strlen(tok.value);
maj_stat = gss_str_to_oid(&min_stat, &tok, oid);
if (maj_stat != GSS_S_COMPLETE) {
// display_status("str_to_oid", maj_stat, min_stat);
return;
}
if (mechstr)
free(mechstr);
}
int main(argc, argv)
int argc;
char **argv;
{
/* char *service_name, *hostname, *msg; */
char *msg;
char service_name[128];
char hostname[128];
char *mechanism = 0;
u_short port = 4444;
int use_file = 0;
OM_uint32 deleg_flag = 0, min_stat;
display_file = stdout;
/* Parse arguments. */
argc--; argv++;
while (argc) {
if (strcmp(*argv, "-port") == 0) {
argc--; argv++;
if (!argc) usage();
port = atoi(*argv);
} else if (strcmp(*argv, "-mech") == 0) {
argc--; argv++;
if (!argc) usage();
mechanism = *argv;
} else if (strcmp(*argv, "-d") == 0) {
deleg_flag = GSS_C_DELEG_FLAG;
} else if (strcmp(*argv, "-f") == 0) {
use_file = 1;
} else
break;
argc--; argv++;
}
if (argc != 3)
usage();
if (argc > 1) {
strcpy(hostname, argv[0]);
} else if (gethostname(hostname, sizeof(hostname)) == -1) {
perror("gethostname");
exit(1);
}
if (argc > 2) {
strcpy(service_name, argv[1]);
strcat(service_name, "#");
strcat(service_name, hostname);
}
msg = argv[2];
if (mechanism)
parse_oid(mechanism, &g_mechOid);
/* if (call_server(hostname, port, g_mechOid, service_name,
deleg_flag, msg, use_file) < 0)
exit(1);*/
/*
if (g_mechOid != GSS_C_NULL_OID)
(void) gss_release_oid(&min_stat, &gmechOid);
*/
return 0;
}
gssapi.h
/* New for V2 */
OM_uint32 KRB5_CALLCONV
gss_str_to_oid(
OM_uint32 *, /* minor_status */
gss_buffer_t, /* oid_str */
gss_OID *);
You just can't include the header you have to link the library either dynamically or statically. Is there some dll, lib, so, etc you need to add to your project? Without makefile or your project setup been shown in your question; I think you will not receive a very clear answer. Just including header file isn't enough, the undefined is not a compilation error but a linker error, which means its missing a reference because you are not linking the library to your program.
The documentation for GSSAPI in C and C++ in not the greatest. Turns out you need to download gssapi. Here is the link http://www.gnu.org/software/gss/manual/gss.html.
It is under download and install
So, I faced same problem.
I found out that you need to add some .so files to your project.
Just in case check that your system has libkrb5-dev packet (most likely it is already installed if you have gssapi.h).
Required files are stored in folder "/usr/lib/x86_64-linux-gnu/" (debian in my case):
I added libkdb5.so and libgssapi_krb5.so to QT .pro file and all works fine:
LIBS += -lkdb5
LIBS += -lgssapi_krb5
If you need to find that files .so use folloing commands:
apt-file update
dpkg -L libkrb5-dev

The shell I am writing does not exit correctly after execvp() fails

I have an assignment to make a shell in C code, and I have a solution that works most of the time. My solution works if the program exists, and I can exit my shell with either Control-D or by typing exit. But when I try a command that I know doesn't exist, my shell will print an error message saying command not found but I will have to either type exit or press Control-D the same amount of times as a invalid command was entered i.e. if I type a wrong command 3 times, I then have to hit Control-D 3 times. I really don't know what is going on here. I checked all the variables and read is -1 when I press Control-D but the if statement seems to be skipped.
Here is the parts of my source code that I think the problem is in:
comp20200Shell.c
#include "comp20200Shell_header.h"
#include <signal.h>
/*
* Name: ****
* Student Number: ****
* Email: ****
*
* This is the main function of my shell implementation.
*
*/
int main(void)
{
bool end_program = false;
size_t length = 0;
ssize_t read;
char* current_directory = NULL;
char* current_time = NULL;
/* Sets up signal handler to catch SIGINT*/
if(signal(SIGINT, sigintHandler) == SIG_ERR)
{
error("An error occured while setting a signal handler\n");
}
/* Infinitive loop, so after command or invalid comman will prompt again*/
while(end_program != true)
{
char* input = NULL;
/* Gets current working directory */
current_directory = return_current_directory();
/* Gets current date and time */
current_time = return_time();
/* Prints Prompt */
printf("%s\x5b%s\x5d %s%s %s%s%s", MAGENTA_TEXT, current_time, GREEN_TEXT, current_directory, BLUE_TEXT, PROMPT, RESET_COLOUR);
/* Frees the pointers returned by return_time() and return_current_directory() */
free(current_time);
free(current_directory);
/* Reads one line from standard input */
read = getline(&input, &length, stdin);
/* Checks if ctrl d, i.e. end of file is found or exit is typed */
if(strcmp(input, "exit\n") == 0 || read == -1)
{
if(read == -1)
{
putchar('\n');
}
/* Frees input */
free(input);
return(0);
}
/* Removes newline character that will be at the end */
remove_trailing_newline(input);
/* Passes input to process input, and the return value is passed in to process errors */
process_errors(process_input(&input));
/* Frees input */
free(input);
}
return(0);
}
process_input.c
#include "comp20200Shell_header.h"
#include <sys/wait.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
/*
* Name: ****
* Student Number: ****
* Email: ****
*
* This function is used to process the command entered by the user
*
* return: the error value or 0 when everything whent ok
* arguments: the command entered by the user
*
*/
int process_input(char** input)
{
bool redirect_stdout = false;
bool redirect_stderr = false;
pid_t child_pid;
int child_status;
char** argument = malloc(sizeof(char*));
int count = 0;
char* temp = strtok(*input, " ");
while(temp != NULL)
{
argument[count] = temp;
count ++;
argument = realloc(argument, (count+2) * sizeof(char *));
temp = strtok(NULL, " ");
}
argument[count] = NULL;
if(argument[0] == NULL)
{
return(0);
}
else if(strcmp(argument[0], "cd") == 0)
{
return(change_directory(argument[1]));
}
int index;
for(index = 1; argument[index] != NULL; index++)
{
if(strcmp(argument[index], ">0") == 0)
{
if(argument[index + 1] == NULL)
{
return(EINVAL);
}
redirect_stdout = true;
break;
}
else if(strcmp(argument[index], ">2") == 0)
{
if(argument[index + 1] == NULL)
{
return(EINVAL);
}
redirect_stderr = true;
break;
}
}
child_pid = fork();
if(child_pid == 0)
{
int file;
if(redirect_stdout == true)
{
file = open(argument[index + 1], O_WRONLY|O_CREAT|O_TRUNC, 0666);
dup2(file, 1);
edit_arguments(argument, index);
execvp(argument[0], argument);
return(-1);
}
else if(redirect_stderr == true)
{
file = open(argument[index + 1], O_WRONLY|O_CREAT|O_TRUNC, 0666);
dup2(file, 2);
edit_arguments(argument, index);
execvp(argument[0], argument);
return(-1);
}
execvp(argument[0], argument);
return(-1);
}
else
{
wait(&child_status);
}
return(child_status);
}
comp20200Shell_header.h
/*
* Name: ****
* Student Number: ****
* Email: ****
*
* This is my header file, It includes all common used headerfiles on the top.
* Any specific header file that is only used once will be included with the .c file that needs it.
*
*/
/* included headerfiles begin */
#include <ctype.h>
#include <string.h>
#include <stdlib.h>
#include <stdio.h>
#include <unistd.h>
#include <errno.h>
#include <stdbool.h>
/* included headerfiles end */
/* defenitions begin */
#define PROMPT "# "
#define BUFFER_SIZE 1024
#define BLUE_TEXT "\x1B[34m"
#define MAGENTA_TEXT "\x1B[35m"
#define GREEN_TEXT "\x1B[32m"
#define RESET_COLOUR "\x1B[0m"
/* defenitions end */
/* Function prototypes begin */
void remove_trailing_newline(char *input);
void sigintHandler(int sig_num);
int process_input(char** input);
char* return_time(void);
void error(const char *fmt, ...);
int change_directory(char* path);
char* return_current_directory(void);
void process_errors(int return_value);
void edit_arguments(char** argument, int index);
/* Function prototypes end */
I have omitted the rest of the source code as I don't think the problem is there.
In your child, after the call to execvp you need to call exit(EXIT_FAILURE); instead of return -1;. Otherwise your child will continue running, and will interpret the next command (that is why you need to exit N times where N is the number of inexistant commands you tried to invoke).
After the change, your parent process will see that the child terminated with a non-zero return code and should interpret the error code. There is no real way to distinguish between a failure from the execvp (due to a non-existent command) or from the invoked process. I would recommend printing the error from execvp if there is one in the child before the exit.
Note that if execvp succeed, it will never return, so the code following a call to execvp can only be executed if the command failed.
So, my recommendation is doing this:
if(child_pid == 0)
{
int file;
if(redirect_stdout == true)
{
file = open(argument[index + 1], O_WRONLY|O_CREAT|O_TRUNC, 0666);
dup2(file, 1);
edit_arguments(argument, index);
execvp(argument[0], argument);
perror("execvp");
exit(EXIT_FAILURE);
}
else if(redirect_stderr == true)
{
file = open(argument[index + 1], O_WRONLY|O_CREAT|O_TRUNC, 0666);
dup2(file, 2);
edit_arguments(argument, index);
execvp(argument[0], argument);
perror("execvp");
exit(EXIT_FAILURE);
}
execvp(argument[0], argument);
perror("execvp");
exit(EXIT_FAILURE);
}
else
{
wait(&child_status);
}
You should be doing exit(1); or equivalent instead of return(-1);. You might want to use _exit(1);, or _exit(255); (or _exit(-1);, but it is equivalent to _exit(255);). You might well want to print an error message to standard error before you exit.
When you don't exit, you end up with two, then three, then N shells all trying to read input from the terminal. You have to make each one quit separately by indicating EOF with Control-D. If you tried typing commands, then it would become a lottery which shell gets each character, and that leads to chaos (and grave danger; you may have thought you typed grep fungible form.file | tr -d 'fr' > /tmp/x33 but if one of the shells got rm -fr /, you've got trouble!).
Instead of return -1, you can use exit(1) or exit (-1) to exit from that portion if it fails to execute due to some error.

Listing directories in Linux from C

I am trying to simulate linux command ls using linux api from c. Looking at the code it does make sense, but when I run it I get "stat error: No such file or directory". I have checked that opendir is working ok. I think the problem is in stat, which is returning -1 even though I think it should return 0.
What am I missing?
Thanks for your help.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <dirent.h>
#include <sys/stat.h>
#include <errno.h>
int main(int argc, char *argv[])
{
DIR *dirp;
struct dirent *direntp;
struct stat stat_buf;
char *str;
if (argc != 2)
{
fprintf( stderr, "Usage: %s dir_name\n", argv[0]);
exit(1);
}
if ((dirp = opendir( argv[1])) == NULL)
{
perror(argv[1]);
exit(2);
}
while ((direntp = readdir( dirp)) != NULL)
{
if (stat(direntp->d_name, &stat_buf)==-1)
{
perror("stat ERROR");
exit(3);
}
if (S_ISREG(stat_buf.st_mode)) str = "regular";
else if (S_ISDIR(stat_buf.st_mode)) str = "directory";
else str = "other";
printf("%-25s - %s\n", direntp->d_name, str);
}
closedir(dirp);
exit(0);
}
It's because you aren't stating the actual file. It's in a different directory. If you want the real filename, combine argv[1] and direntp->d_name with a '/' between them.
Also, hungarian naming is icky, even the minor bit like 'p' on the end. If you have so many variables you need to keep track of their types in their names you're doing something wrong.
Here is a revised version of your program:
#include <stdio.h>
#include <stdlib.h>
#include <stddef.h>
#include <string.h>
#include <dirent.h>
#include <sys/stat.h>
#include <errno.h>
#include <limits.h>
#include <sys/param.h>
int main(int argc, char *argv[])
{
DIR *dirp;
struct dirent *direntp;
struct stat stat_buf;
char *str;
char fullpath[MAXPATHLEN + 1];
size_t dirnamelen;
if (argc != 2)
{
fprintf( stderr, "Usage: %s dir_name\n", argv[0]);
exit(1);
}
strncpy(fullpath, argv[1], MAXPATHLEN - 1); /* account for trailing '/' */
fullpath[MAXPATHLEN - 1] = '\0';
dirnamelen = strlen(fullpath);
if (strlen(argv[1]) > dirnamelen) {
fprintf( stderr, "Directory name is too long: %s", argv[1] );
exit(2);
}
fullpath[dirnamelen++] = '/';
fullpath[dirnamelen] = '\0';
if ((dirp = opendir( argv[1])) == NULL)
{
perror(argv[1]);
exit(2);
}
while ((direntp = readdir( dirp)) != NULL)
{
fullpath[dirnamelen] = '\0';
if ((dirnamelen + strlen(direntp->d_name)) > MAXPATHLEN) {
fprintf(stderr, "File %s + directory %s is too long.", direntp->d_name, fullpath);
continue;
} else {
/* strncpy is mild overkill because the if statement has verified that
there's enough space. */
strncpy(fullpath + dirnamelen, direntp->d_name, MAXPATHLEN - dirnamelen);
fullpath[MAXPATHLEN] = '\0';
}
if (stat(fullpath, &stat_buf)==-1)
{
perror("stat ERROR");
exit(3);
}
if (S_ISREG(stat_buf.st_mode)) str = "regular";
else if (S_ISDIR(stat_buf.st_mode)) str = "directory";
else str = "other";
printf("%-25s - %s\n", direntp->d_name, str);
}
closedir(dirp);
exit(0);
}
Note that I use MAXPATHLEN (from <limits.h>) and carefully check to make sure there aren't any buffer overflows. You should do the same in your code.
Edit: Changed code to use strn family functions for added safety.
Add
#include <unistd.h>
...
chdir(argv[1]);
or call stat with the full pathname like this
...
char fullpath[MAXPATHLEN];
snprintf(fullpath, sizeof(fullpath), "%s/%s", argv[1], direntp->d_name);
if (stat(fullpath, &stat_buf) == -1)
...
Others have suggested building a full path for stat(), or using chdir(). Both those will work (although they are subject to a race condition, if the directory is renamed while you are in the middle of reading it).
An alternative, which is not subject to the race condition, and is therefore arguably more "correct", is to use fstatat(). Just replace your existing stat() call with:
fstatat(dirfd(dirp), direntp->d_name, &stat_buf, 0)
(The chdir() method can be made race-condition-free too: either by using fchdir(dirfd(dirp)) instead of chdir(), or by changing directory to argv[1] and then opening "." with opendir(). The pathname construction method can't be made race-condition-free).
Why dont you try this? Just give the path to argv[1] like this /home/sabri/Desktop/Test
int main(int argc, char *argv[])
{
struct dirent *direntp;
DIR *dirp;
if (argc != 2)
{
fprintf(stderr, "Usage: %s directory_name\n", argv[0]);
return 1;
}
if ((dirp = opendir(argv[1])) == NULL)
{
perror ("Failed to open directory");
return 1;
}
while ((direntp = readdir(dirp)) != NULL)
printf("%s\n", direntp->d_name);
while ((closedir(dirp) == -1) && (errno == EINTR)) ;
return 0;
}
If you are using on unix, then you may use the system command.
system("ls -ltr | grep -d");

Resources