I'm building a shell for an Operating Systems class that must use exec() or one of its variants to execute external commands. Currently, I'm using execlp(command,command_parameters, (char *) NULL). This runs the command just fine (e.g. ls returns a standard directory listing), but doesn't seem to parse any of the parameters (e.g. running mkdir hello throws an error "hello: missing operand... Try 'hello --help' for more information). What am I missing?
else // Try to handle an external command
{
char *command_parameters = malloc(sizeof(raw_command)-sizeof(command));
strcpy(command_parameters, raw_command+strlen(command)+1);
pmesg(1, "Command is %s.\n", command);
pmesg(1, "The command parameters are %s.\n", command_parameters);
pid_t pid = fork();
pmesg(1, "Process forked. ID = %i. \n", pid);
int status;
if (fork < 0)
{
printf("Could not fork a process to complete the external command.\n");
exit(EXIT_FAILURE);
}
if (pid == 0) // This is the child process
{
pmesg(1, "This is the child process, running execlp.\n");
if (execlp(command, command_parameters, (char *) NULL) < 0)
{
printf("Could not execute the external command.\n");
exit(EXIT_FAILURE);
}
else { pmesg(1, "Executed the child process.\n"); }
}
else {while(wait(&status) != pid); } // Wait for the child to finish executing
pmesg(1, "The child has finished executing.\n");
}
(pmesg is a debug tag that prints the statement given a certain debug level).
Thanks!
A couple of issues here:
execlp( const char *file, const char *arg, ...) expects the arguments to be split up and passed separately, not as one big string.
The first arg (after const char *file) is by convention, the name of the executable you're running, which gets put into argv[0] in the called program. The first parameter, thus, will need to go after that.
e.g.:
execlp( command, command, arg1, arg2, ..., (char *)NULL );
With what you have, doing it like:
execlp( command, command, command_parameters, (char *)NULL );
will probably, as-is, take care of your issue with "mkdir", "hello", but you're still not splitting the command_parameters string up, so it won't work without modification for commands with more than one argument.
EDIT: P.S. Your line
if (fork < 0)
should be
if (pid < 0)
Related
I am creating a simple Linux command shell in C. I am having trouble understanding where my code is having problems. "commands" is a list of strings of Linux commands that I want to be executed concurrently as the children processes of one parent. When all are done executing, I want the parent to exit the function. However, when I call exit(0), the for loop continues and parses the current command again, causing the args to be executed again in execvp. Am I using fork() and wait() correctly here? I have tried using waitpid() as well with no luck.
void executeShell(char** commands){
char **arr = commands;
char *c;
pid_t pid, wpid;
int status = 0;
for (c = *arr; c; c=*++arr){
// printf("%d-\n", strcmp(command, "exit"));
if (strcmp(c, "exit") == 0){
EXIT = 1;
return;
}
printf("Running command \'%s\'...\n", c);
char** args = parseStringToTokenArray(c, " ");
free(args);
/* fork and execute the command */
pid = fork();
if(pid < 0){
perror("fork() error\n");
return;
}
/* child process executes command */
else if (pid == 0){
/* 'cd' is not a part of /bin library so handle it manually */
if (strcmp(args[0], "cd") == 0){
changeDirectory(args[1]);
}
else if (strcmp(args[0], "sdir") == 0){
searchDirectory(args[1]);
}else{
/* parse commands with arguments */
execvp(args[0], args);//execute the command
}
exit(0);// <-----command is finished, so why no exit?
}
}
/* wait for children to complete */
while((wpid = wait(&status)) > 0);
}
If execvp succeeds, the entire child process address space is replaced by the program invoked by execvp(). This means that the exit(0) will only ever be invoked following your two special cases i.e. cd and sdir. As far as your code is concerned execvp() should never return, unless there is an error.
A further problem is that you free args immediately after allocating it and then go on to use it in your child processes. This is undefined behaviour.
The only problem I see with your wait code is that, if any of the children block waiting for user input, the parent will block waiting for the child to exit.
The cd code, has no effect on any process except the child in which it is executed. The parent's current directory is not affected. As you state in the comments, this can bet fixed by handling cd in the parent without forking.
I'm trying to use fork() and exec() to run another program that resides in the same directery. The compiler is not complaining, but the program I am trying to call using execl() is not being run. Any tips? Thank you!
pid = fork();
if (pid == -1) {
fprintf (stderr, "Error\n");
exit(1);
}
else if (pid > 0) {
wait(&status);
}
else {
execl("./expo.c", "./expo", x, n, (char*) NULL);
_exit(EXIT_FAILURE);
}
I have tried a few different versions of exec() as well and none have worked.
EDIT:
I have changed to execl("expo","expo",&x,&n,(char*)NULL); , though I am still unsure why this works based on the man pages. The man page says the first argument should be a path, not just the executable. Also, why do I not need ./ for the second argument if I would need that to run that executable in the terminal?
I have got everything working correctly, here is what I changed. Instead of casting the arguments (x and n) into ints then passing them to the child, I passed them as chars and then casted them as ints in the child process.
if(pid==-1){
fprintf (stderr, "Error\n");
exit(1);
}
else if(pid>0){
wait(&status);
}
else{
const char *x=argv[1];
const char *n=argv[2];
execl("expo","expo",x,n,(char*)NULL);
perror("execl() failure!\n");
exit(EXIT_FAILURE);
}
I am attempting to use fork/execvp to execute another program from within my C program. It is working, however before ls outputs the contents of my directory I am getting several hundred lines of:
ls: cannot access : No such file or directory
Followed by the correct listing of the files in the directory. I am passing to execvp:
char **argv = {"ls", "/home/school/"};
char *command = "ls";
For some reason when I use the path "/home/school" it cannot find the directory. Does anyone know why that is happening and why ls is saying it cannot access?
PID = fork();
i = 0;
if(i == numArgs) { doneFlag = 1; }
if (PID == 0){//child process
execvp(command, argv);//needs error checking
}
else if(PID > 0){
wait(PID, 0, 0);//wait for child process to finish execution
}
else if(PID == -1){
printf("ERROR:\n");
switch (errno){
case EAGAIN:
printf("Cannot fork process: System Process Limit Reached\n");
case ENOMEM:
printf("Cannot fork process: Out of memory\n");
}
return 1;
}
The execv and execvp functions provide an array of pointers to null-terminated strings that represent the argument list available to the new program.
The first argument should point to the file name associated with the file being executed.
The array of pointers must be terminated by a NULL pointer. Append a 0 or NULL at the end of argv*.
The char** argument passed in execvp() must be terminated by NULL.
I made a simple minishell in C and it works, except for the cd command. When I try to run it nothing happens except it creates a child process that never actually ends. For example, after running cd in my minishell I need to type exit twice to exit the minishell, not the standard once.
Code:
int debug=0;
void safeQuit(){
if (debug==1)
printf("INFO: Parent process, pid=%d exiting.\n", getpid());
exit(0);
}
int main(int argc,char** argv)
{
int pid, stat;
char * Array_arg[50];
char command_line[200];//user input
if (argc>1)
if (strcmp(argv[1],"-debug")==0)
debug=1;
while (1){
printf("[minishell]> "+debug);
gets(command_line);
if (strcmp(command_line,"exit")==0)
safeQuit();
char * subcommand=strtok(command_line," "); //divides the string according to the spaces
int i=0;
while (subcommand!= NULL)//insert to array
{
Array_arg[i]=subcommand;
subcommand=strtok(NULL," ");
i++;
}
Array_arg[i]='\0';
if (fork()==0){
if (debug==1)
printf("INFO: child process, pid = %d, executing command %s\n", getpid(), command_line);
execvp(Array_arg[0],Array_arg); //execution of cmd
}
else{
pid=wait(&stat);
}
}
}
cd is necessarily a shell built-in, not an external utility. You want to change the current working directory of the current process (the shell itself), not of a child process. Call chdir instead of forking a child process.
Separately, check execvp for errors and defensively terminate the child after a failed exec. You'd have seen an informative error if you had done so:
... (child) ...
execvp(Array_arg[0], Array_arg);
perror("Error - exec failed"); // If we are here, we did *not* replace the process image
exit(0);
I am creating a simple Unix shell in C. I use the fork() to clone the process and exec to execute a new one. It works fine when you are inputting data for the first time in the shell. But when it comes the second iteration fork returns -1.
e.g
...>ls -l /
/results here/
...>ls -l /
forking failed
here is a part of the code:
int execute(char path[80],char *args[]){
pid_t pid;
if((pid=fork())<0){
printf("forking failed"); // The forking failed due to Cannot allocate memory error
exit(0);
}else if(pid==0){
execv(path,args);
}else{
wait(NULL);
}
return 0
}
where path is "bin/ls" and args "ls",NULL
the main is looks like
int main(){
while(1){
//read from keyboard
//find the program path
//fill args
execute(path,args);
}
}
Change your first if branch to this:
if((pid=fork())<0){
perror("forking failed");
exit(0);
}
This will tell you what went wrong.