execvp() wont load file: "No such file or directory" - c

I wrote 2 programs.
The first one gets 2 strings through argv and prints the program process id and the smallest string (by dictionary order).
int main(int argc,char **argv) {
int cmp;
if (argc != 3){
perror("Wrong arguments");
exit(EXIT_FAILURE);
}
printf("my ID: %d\n",getpid());
cmp = strcmp(argv[1],argv[2]);
if (cmp < 0)
puts(argv[1]);
else if (cmp > 0)
puts(argv[2]);
else puts(argv[1]);
exit(EXIT_SUCCESS);
}
I have compiled the code via terminal with:
gcc -Wall my_cmp.c -o my_cmp
The second program creates a child process and performs execvp() with my_cmp sending "abc" "de".
void do_sun(char **argv);
int main() {
pid_t status;
char *args[] = { "my_cmp", "abc","de", NULL };
status = fork();
if (status < 0){
perror("Cannot fork");
exit(EXIT_FAILURE);
}
if (status == 0){
char *args[] = { "my_cmp", "abc","de", NULL };
do_sun(args);
exit(EXIT_SUCCESS);
}
if (status > 0){
wait(&status);
if (execvp(args[0],args) != 0 )
perror("error");
exit(EXIT_SUCCESS);
}
exit(EXIT_SUCCESS);
}
void do_sun(char **args){
if (execvp(args[0],args) == -1 )
perror("error");
exit(EXIT_SUCCESS);
}
When I run the program I am getting this message:
error: No such file or directory
error: No such file or directory
I have tried to switch directory to the my_cmp file with no success.

On some systems it won't search working directory for executable binary files by default.
You should use ./my_cmp instead of my_cmp to have it work on such systems.

If you use execvp, you are saying that the executable will be found "in the path"; that is, in one of the directories listed in $PATH. Few directories are on this path, and while it is possible to add . to $PATH, that's generally regarded to be asecurity vulnerability.
If you want to specify the path to the executable (in which case you can put it in whatever directory you want), use the non-path execv.

Related

Custom shell stops working after dup2

I am writing a function to my shell where I need to redirect output to file. For example user write: ls -l >> file and ls -l should be written to file. Almost all things are correct but after first calling my function program stop and I can't write anything else. Below I present my function and I would appreciate any clues to resolve the problem:
void execute2(char *command, char **argv, char **argv2)
{
pid_t pid;
int status;
if ((pid = fork()) < 0)
{
printf("*** ERROR ***\n");
exit(1);
}
else if (pid == 0)
{
close(1);
parse(command, argv, argv2);
int output = open(*argv2, O_APPEND | O_WRONLY);
dup2(output,1);
if (strcmp(argv[0], "exit") == 0)
exit(0);
if (execvp(*argv, argv) < 0)
{
printf("*** ERROR ***\n");
exit(1);
}
close(output);
}
else
{
while (wait(&status) != pid);
}
}
command is command getting from user, argv is part of instruction and parameters and argv2 is the output file.
#Jonathan Leffler I checked this and I think it doesn 't resolve problem. I suggest that when I call first time execute2 it works as well as I want but I never finish that proces. Or I don 't undestand something

Why isn't chdir() working? [duplicate]

This question already has an answer here:
How can I use chdir function in Linux?
(1 answer)
Closed 6 years ago.
When I try to run ./shell cd includes/
I don't actually change into the includes directory. Here's my code:
int cd(char *path) {
printf("i got there at least\n");
if(path == NULL) {
printf("dont waork\n");
print_usage();
} else {
printf("print please\n");
int dir_change = chdir(path);
if(dir_change != 0)
print_no_directory(path);
}
return 1;
}
int shell(int argc, char *argv[]) {
pid_t pid;
int status;
pid = fork();
if(pid == 0) {
execl("cd", argv[0], argv[1], argv[2], (char*)NULL);
printf("argv[1]: %s\n", argv[1]);
if(!strcmp(argv[1], "cd")) {
cd(argv[2]);
}
} else if(pid > 0) {
waitpid(pid, &status, WUNTRACED);
} else {
print_fork_failed();
}
return 0;
}
I don't see what's wrong with my code.
You can't run a program to change the directory of another program (your shell).
What happens is
A new process is spawned to run your program
That program calls chdir(), to change its current directory
The program end, causing the process to die
The shell is still where it was
That's why cd in the shell is a built-in command.
you cannot create a cd command like this unless you develop your own shell.
The chdir command works, but only inside your program. Once you exit it, you're back to the parent shell current directory.

Dummy Shell in C get bugged after closing external process

I am writing a shell for an assignment in C. My only problem now is that when I call an external program with execvp() and then close is using CTRL + C, any further commands that I send are printed after the prompt not before it. I made an dummy program that is just an infinite loop to test this.
So after closing this program if I try and run a program that doesn't exist, it will print out
MINISHELL (cwd) $: and then a blank line
and then it will print my error message saying that I have entered a program that does not exist and then it will not print a prompt since it already has. So It ends with an empty new line and it appears that the program has not ended but it actually has.
It ONLY does this after I have closed a non terminating program with CTRL + C. Otherwise it works fine executing programs. Am I not using close() somewhere to close a file descriptor? I am not sure. Any help is appreciated. Thank you.
#include "minishell.h"
void intHandler(int sig)
{
my_char('\n');
}
int main(int argc, char **argv)
{
int n;
int pid = 0;
char* s = (char*)malloc(256*sizeof(char));
char cwd[1024];
char** input;
while (1)
{
signal(SIGINT, intHandler);
my_str("MINISHELL:");
if (getcwd(cwd, sizeof(cwd)) != NULL)
my_str(cwd);
else
{
my_str("Error in current directory");
return -1;
}
my_str(" $: ");
n = read(0, s, 256);
s[n] = '\0';
if (n > 1)
{
input = my_str2vect(s);
if (my_strcmp(input[0], "cd") == 0)
{
/*CHANGE DIRECTORY*/
if (input[1] != '\0')
{
if (chdir(input[1]) < 0)
my_str("MINISHELL: Error in path. Make sure the directory exists.\n");
}
else
my_str("MINISHELL: Error. No directory specified.\n");
}
else if (my_strcmp(input[0], "help") == 0)
{
/*HELP*/
my_str("\nMINISHELL COMMANDS:\n\ncd *directory\nChanges the current working directory to *directory\n\nexit\nExits the minishell\n\nhelp\nPrints a help message listing the built in commands\n\n");
}
else if (my_strcmp(input[0], "exit") == 0)
{
/*EXIT*/
my_str("Thank you for using MINISHELL\n");
exit(0);
}
else if (input[0] != NULL)
{
/*EXECUTE AN EXTERNAL PROGRAM*/
if ((pid = fork()) < 0)
my_str("MINISHELL: Error forking\n");
else if (pid > 0)
{
wait(NULL);
}
else
{
if (execvp(input[0], input) < 0)
{
my_str("MINISHELL: Error. Program does not exist in current directory.\n");
}
else
{
exit(0);
close(0);
}
}
}
else
{
my_str("MINISHELL: Error reading command. Type help to see available commands.");
}
}
}
return 0;
}
You cannot expect that the error message will always print before your prompt. The forked process is running in parallel with your main program. The order in which the output to stdout from the two programs occur is dependent upon how the OS scheduler runs the processes.
I think most real shells like bash actually do the check for the file existing in the main process before doing the fork(). Alternatively you could use pipe() and manually redirect the output. Then you can enforce flushing the entire contents before doing your prompt.

execve error: no such file or directory

I'm trying to write a program to execute and schedule a list of processes. My code for main.c is below. When run, I receive an error from perror saying there is no such file or directory. I'm guessing this is because the files/programs in my files.txt are not binary executables but I'm not sure how to fix this. files.txt contains the list of programs I want to run. They have all been converted to binary executables already. programs is an array containing the four programs that have been read by the readPrograms function
int main(int argc, char ** argv) {
pid_t pid[50];
pid_t wpid;
int i, j;
int status = 0;
char *newenvp[] = {NULL};
char *newargv[] = {"./files.txt", NULL};
printf("Before forking in the parent\n");
int numProgs = readPrograms();
for (i=0; i<numProgs; i++) {
pid[i] = fork();
if (pid[i] < 0) {
perror("fork error");
exit(EXIT_FAILURE);
}
else if (pid[i] == 0) {
printf("Child process running\n");
execve(programs[i], newargv, newenvp);
perror("execve error");
exit(EXIT_FAILURE);
}
}
for (i=0; i<numProgs; i++) {
wait(&status);
}
return 0;
}
char* programs[50];
int readPrograms();
files.txt below
./first
./second
./third
./fourth
(I did "cc first.c -o first" for all of these files respectively)
I suspect the bug is in the code you're not showing, readPrograms. Most likely you're reading the lines of the text file with fgets and each string has a newline on the end of it, whereas your filenames don't have newlines in them.

grep doesn't work in custom shell

I'm trying to write a shell in c and it mostly works except for grep. Whenever I give a grep command in the shell, it just doesn't output anything. Here is the part of the code I use to create a new child process and then run execvp() in it.
The file descriptors(fd_in and fd_out) in dup2 are passed as arguments to the function which has this code. And most interestingly, when I give 'grep' or 'grep --help' it displays as usual. Am I missing anything? Or something special has to be done with grep?
This is what happens with my shell: The last command outputs when run from bash.
--> grep
Usage: grep [OPTION]... PATTERN [FILE]...
Try `grep --help' for more information.
--> wc /etc/hosts
11 33 314 /etc/hosts
--> grep -i "perror" shell.c
-->
Here is the code :
void
create_process(char *cmd_argv[], int fd_in, int fd_out, char *buffer_copy) {
/*Flag bit for Background processes*/
int FLAG = 0;
pid_t cpid;
int status;
int i = 0,j = 0;
/*Find the no. of arguments*/
while(cmd_argv[j] != NULL)
j++;
/*Set the flag bit*/
if(strcmp("&", cmd_argv[j-1]) == 0) {
FLAG = 1;
cmd_argv[j-1] = NULL;
}
//Create a child process
cpid = fork();
if (cpid == -1) {
perror("fork");
exit(EXIT_FAILURE);
}
//In the child...
if (cpid == 0) {
/*Checking if the file descriptors are already assigned*/
/*For stdin*/
if (fd_in != STDIN_FILENO) {
dup2(fd_in, STDIN_FILENO);
close(fd_in);
}
/*For stdout*/
if (fd_out != STDOUT_FILENO) {
dup2(fd_out, STDOUT_FILENO);
close(fd_out);
}
/*Run the cmd specified*/
status = execvp(cmd_argv[0], cmd_argv);
/*In case of errors*/
if(status < 0) {
perror("execvp ");
exit(1);
}
}
//In the parent...
else {
if(FLAG == 1) {
/*Find where the new bg process can be inserted*/
while(1) {
if (bgprocess[i].pid == 0) {
bgprocess[i].pid = cpid;
strcpy(bgprocess[i].cmd, buffer_copy);
break;
}
i++;
}
printf("[%d] : %s\n", cpid, cmd_argv[0] );
}
/*If not bg, wait for the process to exit*/
else
waitpid(cpid, NULL, 0);
}
}
The problem is using the quotes in your shell. Bash does a lot of things in background.
grep -i perror shell.c should give you output on your shell, whatever is anticipated when run from bash.
Quoth man dup2:
After a successful return from one of these system calls, the old and
new file descriptors may be used interchangeably. They refer to the
same open file description (see open(2))…
Therefore after after your call to dup2 (which you should be checking for error returns) you close oldfd and newfd because they are the exact same descriptor.
What I can't figure out is why grep --help works at all but you aren't showing enough code to answer that question.
Added following comment: You still aren't giving enough code. If grep isn't working than what is? Does wc /etc/hosts work? There is nothing special about grep at all, indeed it is a completely unspecial Unix filter.

Resources