Finding the adress of file knowing the name in C - c

I am writing my own shell in C/Ubuntu for a project but I had some diffuculties when using chdir() to implement cd. chdir() needs a path name but since the user will write (lets assume) cd Desktop, Desktop is not a path name so the program will fail.
Here is that part of my code:
child = fork();
if (child == 0) {
if (!strcmp(args[0], "ls")) {
execv("/bin/ls", args);
}
if (!strcmp(args[0] , "cd")) {
chdir(args[1]);
}
perror("Error");
exit(1); //Failure
} else {
do {
waitpid(child, &status, WUNTRACED);
} while(!WIFEXITED(status) && !WIFSIGNALED(status));
So I think the problem is that args[1] gets things like "Desktop" etc instead of the address so chdir fails. I tested it in terminal, all other commands work except cd. My question is that how can I make this chdir work?In another words how can I give the path of args[1] to chdir?
Let me put it in this way. When I write cd Desktop to terminal it works. When I write cd Desktop to my own shell it tries to execute chdir("Desktop") and it fails.

You use use exec to run the ls command, I suspect you fork() the process before selecting which command to execute: chdir(args[1]) is executed in the child process, the child process changes its current directory and then exits. Each process has its own current directory. The parent (shell) process current directory in unaffected by the change in its child, it keeps its current directory.
Most command should be executed in the shell process without forking, only external commands should be executed after forking to a child process.
Here is a modified version of your code:
/* frist execute local commands in the shell process. */
if (!strcmp(args[0], "cd")) {
if (!args[1]) {
fprintf(stderr, "cd: missing argument\n");
} else
if (chdir(args[1])) {
perror("chdir");
}
} else
if (!strcmp(args[0], "exit")) {
int status = args[1] ? atoi(argv[1]) : 0;
exit(status);
} else {
/* otherwise, fork and attempt to execute an external command */
child = fork();
if (child == 0) {
if (!strcmp(args[0], "ls")) {
execv("/bin/ls", args);
}
/* if exec failed, the child process is still running */
perror("exec");
exit(1); //Failure
} else {
do {
waitpid(child, &status, WUNTRACED);
} while(!WIFEXITED(status) && !WIFSIGNALED(status));
}

Related

Ubuntu-Daemon does not create file

I'm trying to run a simple daemon on Ubuntu 18.04.2 LTS, which should write some data into a log file. The parent process terminates with exit code 0, but no file is created.
Furthermore, when I set a breakpoint after fork(), pid is 835 for example. When I query the process name of this program with ps -p 835 -o comm=, I get LinuxTest.out <defunct>, but when I let the program continue and query the process name again, no output is shown, even though the child process should be still running due to the infinite loop later in the code.
I am using Visual Studio 2019 with Remote Build. I have also tried to log in per SSH into the server and execute the built program there with sudo rights, but nothing happened too.
int main() {
pid_t pid, sid;
// Fork off the parent process
pid = fork();
// if we got a good PID, then we can exit the parent process
if(pid > 0) exit(EXIT_SUCCESS);
else exit(EXIT_FAILURE);
// create new SID for child process
sid = setsid();
if(sid < 0) exit(EXIT_FAILURE);
// change the current working directory
if(chdir("/") < 0) {
exit(EXIT_FAILURE);
}
// change the file mode mask
umask(0);
// close out the standard file descriptors
close(STDIN_FILENO);
close(STDOUT_FILENO);
close(STDERR_FILENO);
// Open a log file in write mode.
FILE* fp = fopen("Log.txt", "w+");
while(1) {
sleep(1);
fprintf(fp, "Logging info...\n");
fflush(fp);
}
fclose(fp);
}
Why is the point to create the file not reached and why doesn't stay the child process alive?
You have:
if(pid > 0) exit(EXIT_SUCCESS);
else exit(EXIT_FAILURE);
When formatted in a more orthodox style, that is the same as:
if (pid > 0)
exit(EXIT_SUCCESS);
else
exit(EXIT_FAILURE);
If the fork() succeeds, the parent exits successfully and the child exits with a failure status; if the fork() fails, the parent exits with a failure status.
Change that to:
if (pid > 0)
exit(EXIT_SUCCESS);
else if (pid < 0)
exit(EXIT_FAILURE);
/* Child is running here: pid == 0 */

Why is execvp() executing twice using fork()?

I am implementing a shell.
When attempting a command other than changing directories, execvp() runs, the child terminates and a new child is created. When I change directories, the child does not terminate and a new child is created. Here is a sample of my code:
for(;;) {
printf("bash: ");
parse();
...
pid_t pid = fork()
if (pid == 0)
if (!strcmp(line[0], "cd"))
if (!line[1]) (void) chdir(getenv("HOME"));
else (void) chdir(line[1]);
else execvp(line[0], line);
...
if (pid > 0) {
while (pid == wait(NULL));
printf("%d terminated.\n", pid);
}
}
cd ../; ls; runs correctly, except I have to Ctrl+D twice to end the program.
Though, if I pipe the same information (ie. mybash < chdirtest), it runs correctly once, terminates the child, runs again except in the original directly, then terminates the final child.
cd should not be invoked through a child process, the shell itself should change its current directory (that's the property of an internal command: modify the process of the shell itself).
A (primitve) shell should looks like:
for(;;) {
printf("bash: ");
parse();
// realize internal commands (here "cd")
if (!strcmp(line[0], "cd")) {
if (!line[1]) (void) chdir(getenv("HOME"));
else (void) chdir(line[1]);
continue; // jump back to read another command
}
// realize external commands
pid_t pid = fork()
if (pid == 0) {
execvp(line[0], line);
exit(EXIT_FAILURE); // wrong exec
}
// synchro on child
if (pid > 0) {
while (pid == wait(NULL));
printf("%d terminated.\n", pid);
}
}

implementing a shell in C

im currently implementing a shell in C.
My problem arises when i try to run a command like this:
SHELL$: sort < txtFile | grep key
im running sort < txtFile in a process (child), and in the parent i.e else if(pid > 0) im running the other command to the right of the pipe.
The program runs fine, but it exits the infinite loop that i set up in main to keep receiving input from the user.
How could i solve this problem?
this is the code i have so far to deal with the pipe, i didnt include the code that i have to deal with the redirects:
c2p is the pipe i setup for this.
if(pid == 0)
{
if( PIPE_FLAG )
{
close(c2p[0]);
if(dup2(c2p[1], STDOUT_FILENO) == -1){
perror("dup2() failed");
exit(2);
}
}
/* Execute command */
execvp(cmd_args[0], cmd_args);
perror("exec failed 1. "); /* return only when exec fails */
exit(-1);
}
else if(pid > 0)
{
if(PIPE_FLAG)
{
close(c2p[1]);
if(dup2(c2p[0], STDIN_FILENO) == -1){
perror("dup2() failed");
exit(-1);
}
execvp(nxt_args[0], nxt_args);
perror("exec failed 2. ");
exit(-1);
}
}
else
{
/* error occurred */
perror("fork failed");
exit(1);
}
I'm running sort < txtFile in the child process, and in the parent I'm running the command to the right of the pipe.
What happens to your shell process, then? The parent process is the shell. By running the right-side command in the parent process you're having it take over the shell's process. Remember that exec() replaces the current process.
You'll need to fork() twice, and execute the two sides of the pipe in the child processes. The parent must remain the shell, which will then wait() for the children to exit before presenting the next command prompt.
/* How shell works */
#include<stdio.h>
#include<unistd.h>
main (int argc, char **argv)
{
if (argc < 2)
{
fprintf (stderr, "\nUsage: ./a.out cmd [options]...\n");
}
if (!fork ())
{
argv++;
execvp (argv[0], argv);
}
}

Redirecting forked process output to parent process in C

What I am implementing is a (simpler) version of bash. One of the tasks is to accept the command :
$ bg <command> <arguments>
This will then fork a new process and then run execvp() in the new process using <command> and <arguments> as parameters. The problem is that when I capture the output from the child process, I use pipe(), and after getting the output from the child process and outputting it when I want, I can't seem to switch back to STDIN for my parent (shell) process, which results in a segfault the next time I need to accept input.
Here is part of my "bg" function.
ChildPID = fork();
if (ChildPID < 0) {
/* There is an error */
printf("Error forking the process.\n");
exit(1);
}
if (ChildPID >= 0) {
if (ChildPID == 0) { /* Child Process */
close(m_pipefd[0]);
dup2(m_pipefd[1], STDOUT_FILENO);
close(m_pipefd[1]);
//sleep(5);
err = execvp(optionsPTR[0], optionsPTR);
switch (errno) {
case ENOENT:
printf("RSI: %s: command not found\n", optionsPTR[0]);
break;
case EACCES:
printf("RSI: %s: Permission denied\n", optionsPTR[0]);
break;
}
exit(1);
}
else { /* Parent Process */
WaitErr = waitpid(ChildPID, &status, WNOHANG | WUNTRACED);
return(0); /* to main */
}
}
return 0;
And the code for when I get the output from the pipe after the process finishes.
close(m_pipefd[1]);
dup2(m_pipefd[0], STDIN_FILENO);
while(fgets(buffer, sizeof(buffer), stdin)) {
buf = buffer;
printf("%s\n", buf);
}
close(m_pipefd[0]);
So the tl;dr version is that I need to reset back to stdin for the parent process after capturing the child processes output.
Thanks,
Braden
There is usually no need to mess with stdin and stdout in your parent. After you connect your pipes in the child to stdin and stdout, the other ends of the pipes should be able to send data or get data from the child.
Just read from m_pipefd[1] in your parent.

How to handle inputs in a C shell program during exec

I am currently writing my own shell program. This simple shell can just execute commands.
When executing commands like vi or calc which require input from the terminal , the command is getting executed and is waiting for the input from the user. But I am unable to give any input on the screen.
How should the input be handled during the fork and exec.
Here is the piece of code which is executing commands:
if((pid = fork()) < 0)
{
perror("Fork failed");
exit(errno);
}
if(pid == 0)
{
// Child process
if(execvp(arguments[0], arguments) == -1)
{
child_status = errno;
switch(child_status)
{
case ENOENT:
printf(" command not found \n");
break;
}
exit(errno);
}
}
else
{
// parent process
int wait_stat;
if(waitpid(pid , &wait_stat, WNOHANG) == -1)
{
printf(" waitpid failed \n");
return;
}
}
}
~
Thanks,
The WNOHANG is causing the parent process not to wait and therefore (depending on platform) the child process will be detached from terminal IO or die.
Remove the WNOHANG.

Resources