I am writing a program in C in one of my systems classes. We write c code and run it in a unix environment. I have looked all over the internet, but can't seem to find any way to make the kill(int PID) command work. The code will compile and run fine, but if I use the
ps -u username
command in a unix command prompt (after execution has completed of course,) it says that the all of the processes I tried to kill in my c code are still running. I can kill them from the unix command prompt by manually entering their PIDs, but for the life of me, I cannot figure out how to do it inside of my program.
In this particular program, I am trying to kill process CC, which is a process that just infinitely calls usleep(100); until terminated.
I tried using kill(C3, -9); and variations of execlp("kill", "kill", C3, (char *)0); but still no luck. Does anyone have any idea what I am doing wrong here? My only guess is that the kill command is being passed the wrong PID parameter, but if that's the case, I have no idea how I would get the correct one.
EDIT: Also, the kill command returns a value of zero, which I believe means that it "succeeded" in executing the command.
EDIT: Just noticed that the solution to my problem was in the instructions for the assignment all along. Yup. I'm stupid.
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
int main(int args, char* argv[])
{
//
//Step 7
//
//Create process C3
int C3=fork();
if (C3==0)
{
execlp("CC", "CC", (char *)0);
}
else
{
usleep(500000);
//
//Step 8
//
int ps=fork();
if (ps==0)
{
execlp("ps", "ps", "-u", "cooley", (char *)0);
}
else
{
wait(NULL);
kill(C3);
}
}
exit(0);
}
You're calling the kill system call with only one argument, when it takes two. This leads to undefined behavior since then the second argument can by anything. You should get a warning about this when compiling.
The second argument should be a value from <signal.h> (see the signal(7) manual page).
Related
I'm trying to write a C program that restarts itself once. My approach was to fork and in the child process call execve. I thought I would see Hello twice printed. This here prints main twice, but even so if I comment out execve, so I assume I'm not correctly using execve here. The binary is called "restartOnce".
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <wait.h>
int main(int argc, char *argv[]) {
pid_t pid = fork();
printf("Main.\n");
if (pid == 0) {
char *argv = "hello"; // To silence gcc compiler warning.
char *env = "world"; // To silence gcc compiler warning.
execve("restartOnce", &argv, &env);
} else {
wait(NULL);
printf("Done.\n");
}
return 0;
}
I'm not completely sure what you're trying to accomplish, but I see two things to attend to. We have to get the execve() call right, plus we have to avoid a fork bomb, and this code should do it.
There are lots of ways to avoid a fork bomb, but I chose to set something in the environment, and when the child sees this environment variable, it will know not to continue.
So execve() requires its own argv, which is an array of pointers to individual strings (with a NULL pointer at the end), and it's entirely legit to pass the same parameter you got from main.
The third parameter is like argv, but it's a list of environment variables instead of command line arguments. It has things like TERM=vt100, PATH=/bin/..., and many others. Though you can fetch environment variables individually with getenv("PATH"), Unix/Linux systems provide an argv-like variable environ.
This variable is declared in <unistd.h> but requires the _GNU_SOURCE macro to be defined to expose it.
This done, you can call safely call execve this way:
#define _GNU_SOURCE
#include <unistd.h>
...
execve("restartOnce", argv, environ);
To avoid a fork bomb, one of the first thing the program does is look for the environment variable FORKBOMB - if this is set, we're in the child process and should stop forking other children, perhaps doing something else instead (the real work of the program?)
But if we're in the parent - no variable seen - we actively set the variable by putting it in our own environment that's seen by the child processes: putenv("FORKBOMB=no");
A minor addition: the very first thing the program does is report that it's started up, and it provides its own process ID just so you know what it's doing.
Maybe I misunderstand the problem, but this is how I'd solve what I imagine you're asking:
#define _GNU_SOURCE // for "environ"
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <wait.h>
int main(int argc, char *argv[])
{
printf("Main in pid %d.\n", getpid() );
if (getenv("FORKBOMB") != 0)
{
printf("**We're in the second child, no more forking\n");
exit(0);
}
putenv("FORKBOMB=no");
pid_t pid = fork();
if (pid == 0) {
execve("restartOnce", argv, environ);
} else {
wait(NULL);
printf("Done.\n");
}
return 0;
}
There are quite a few other ways to avoid the fork bomb, but this is as good as any to get the idea across, and others might chime in with their favorites.
EDIT But as I think about this, I'm pretty sure this should not be necessary no matter what you're trying to accomplish unless this is just a learning exercise.
The two things I can imagine are:
1) You need to detach from the parent process so you can run in the background, like a daemon process. In that case, you don't have to exec, just do the daemon work in the child process.
2) If the program has altered itself - perhaps downloaded an updated version of itself, then it does have to call exec to get the new executable, but a fork() would not be required.
So I'm not sure we (or at least I) know what you're trying to accomplish.
I'm having trouble understanding how to do basic piping in C. I looked at a couple other questions on this topic, and either they were for subtly different issues, or I'm so far off the mark on this subject I couldn't understand why the answers are good for my problem.
This program below is just a simple test I made, where I'm trying to get behaviour equivalent to typing "ls | grep a" into my shell. (I have a homework assignment where I have to build a shell that can handle piping, but this is my first step towards understanding pipes to even attempt the homework). I get the correct output, but the terminal prompt ends up appearing before the output, making it look like it did not properly terminate. Since this is connected to a shell homework, I'm worried that will impact the grade (and it just feels wrong to let it look like that anyway). Any advice?
#include <unistd.h>
#include <sys/wait.h>
#include <stdio.h>
int main()
{
int fdpipe[2];
pipe(fdpipe);
int f1 = fork();
if(f1 == 0)
{
close(fdpipe[1]);
dup2(fdpipe[0],0);
close(fdpipe[0]);
execlp("/bin/grep","grep","a",NULL);
}
else
{
close(fdpipe[0]);
dup2(fdpipe[1],1);
close(fdpipe[1]);
execlp("/bin/ls","ls",NULL);
wait(NULL);
}
return 0;
}
Here's an example of my terminal output.
1067: ls
a.out test.c test.cc
NathanE: ~/Desktop/playground
1068: ./a.out
NathanE: ~/Desktop/playground
1069: a.out
(The beginning of this line is where my cursor is)
What I'm expecting would be:
1067: ls
a.out test.c test.cc
NathanE: ~/Desktop/playground
1068: ./a.out
a.out
NathanE: ~/Desktop/playground
1069: (my cursor would go here)
The child process runs grep, while the parent replaces itself with ls. The wait(NULL) does nothing, because successful exec*() never return.
Because the control returns to the shell immediately after ls completes, the shell can display the next prompt before grep completes.
There are two approaches you can use to avoid this:
fork() both child processes, and wait() for them
Replace the process itself with the last process in the pipe chain
Either will ensure that control is returned to the shell only after the last process in the pipe chain completes.
I am currently writing my own shell implementation in C. I understood the principle behind piping and redirecting the fds. However, some specific behavior with pipes has attracted my attention:
cat | ls (or any command that does not read from stdin as final element of the pipe).
In that case, what happens in the shell is that ls executes and cat asks for a single line before exiting (resulting from a SIGPIPE I guess). I have tried to follow this tutorial to better understand the principle behind multiple pipes: http://web.cse.ohio-state.edu/~mamrak.1/CIS762/pipes_lab_notes.html
Below is some code I have written to try to replicate the behavior I am looking for:
char *cmd1[] = {"/bin/cat", NULL};
char *cmd2[] = {"/bin/ls", NULL};
int pdes[2];
pid_t child;
if (!(child = fork()))
{
pipe(pdes);
if (!fork())
{
close(pdes[0]);
dup2(pdes[1], STDOUT_FILENO);
/* cat command gets executed here */
execvp(cmd1[0], cmd1);
}
else
{
close(pdes[1]);
dup2(pdes[0], STDIN_FILENO);
/* ls command gets executed here */
execvp(cmd2[0], cmd2);
}
}
wait(NULL);
I am aware of the security flaws of that implementation but this is just for testing. The problem with that code as I understand it is that whenever ls gets executed, it just exits and then cat runs in the background somehow (and in my case fail because it tries to read during the prompt of zsh as my program exits). I cannot find a solution to make it work like it should be. Because if I wait for the commands one by one, such commands as cat /dev/random | head -c 10 would run forever...
If anyone has a solution for this issue or at least some guidance it would be greatly appreciated.
After consideration of comments from #thatotherguy here is the solution I found as implemented in my code. Please bear in mind that pipe and fork calls should be checked for errors but this version is meant to be as simple as possible. Extra exit calls are also necessary for some of my built-in commands.
void exec_pipe(t_ast *tree, t_sh *sh)
{
int pdes[2];
int status;
pid_t child_right;
pid_t child_left;
pipe(pdes);
if (!(child_left = fork()))
{
close(pdes[READ_END]);
dup2(pdes[WRITE_END], STDOUT_FILENO);
/* Execute command to the left of the tree */
exit(execute_cmd(tree->left, sh));
}
if (!(child_right = fork()))
{
close(pdes[WRITE_END]);
dup2(pdes[READ_END], STDIN_FILENO);
/* Recursive call or execution of last command */
if (tree->right->type == PIPE_NODE)
exec_pipe(tree->right, sh);
else
exit(execute_cmd(tree->right, sh));
}
/* Should not forget to close both ends of the pipe */
close(pdes[WRITE_END]);
close(pdes[READ_END]);
wait(NULL);
waitpid(child_right, &status, 0);
exit(get_status(status));
}
I was confused with the original link I posted and the different ways to handle chained pipes. From the link to the POSIX documented posted below my original question (http://pubs.opengroup.org/onlinepubs/009695399/utilities/xcu_chap02.html#tag_02_09_02) it appears that:
If the pipeline is not in the background (see Asynchronous Lists), the shell shall wait for the last command specified in the pipeline to complete, and may also wait for all commands to complete.
Both behavior are therefore accepted: waiting for last command, or waiting for all of them. I chose to implement the second behavior to stick to what bash/zsh would do.
I'm trying to solve a problem because I'm learning to use system calls in C. I used a Ubuntu 12.04 64bit.
The statement of the problem says that I need to implement a code that allows to execute a command (cmd2) after the correct end of other command (cmd1). Also says that user can specify both commands and all of the arguments that user wants.
At this point I create this little program:
#include <syscall.h>
#include <unistd.h>
#include <sys/types.h>
#include <stdio.h>
#include <stdlib.h>
int main(void)
{
int cmd1 = system("sleep 5");
if((cmd1 = (-1)))
{
write(1,"error in command 1",18);
}
if(cmd1=(0))
{
write(1, "hello world", 11);
}
return EXIT_SUCCESS;
}
Next, statement says that if the first command doesn't finish correctly the second will not execute, also, user can abort the execution of the cmd1 using Ctrl+\ or Ctrl+4 (SIGQUIT) and the second command (cmd2) using Ctrl+C (SIGINT). If second command is canceled the first must be completed normaly.
I have problems in this second part of the statement because I never used this kind of things in C and also I'm really noob in linux. I tried to read something about SIGQUIT and SIGINT but I don't understand all that I've read probably because there are a lot of things of linux that I've not learned yet.
Can anyone help me please?
Thanks!
I edit the code for this version using if functions. It doesn't work correctly, I'm finding how to check if the first command finishes correctly.
Just to get you started. Let me explain the question because I feel you haven't understood it.
The statement of the problem says that I need to implement a code that allows to execute a command (cmd2) after the correct end of other command (cmd1).
You will will be given two commands by the user cmd1 and cmd2. cmd1 should be executed first.
Next, statement says that if the first command doesn't finish correctly the second will not execute,
ONLY IF cmd1 finished executing normally should cmd2 be executed.
If second command is canceled the first must be completed normaly.
Execution of cmd1 is not dependent on cmd2.
user can abort the execution of the cmd1 using Ctrl+\ or Ctrl+4 (SIGQUIT)
You seem confused here. Here, they mean to say, cmd1 can be abnormally terminated by passing SIGQUIT to it(Ctrl+\ or Ctrl+4), in which case cmd2 should not be executed. You do NOT have to code the signals part. What you have to do is, check how cmd1 was terminated and then execute cmd2 if it was a normal termination else don't execute cmd2.
Note The code in the question was extremely different when the above part was posted.
This was your code on 5:02 AM Wednesday, 20 May 2015 GMT.(Had to include this because you are changing the code too often and too much)
int main(void)
{
int cmd1 = system("sleep 5");
if((cmd1 = (-1)))
{
write(1,"error in command 1",18);
}
if(cmd1=(0))
{
write(1, "hello world", 11);
}
return EXIT_SUCCESS;
}
Here you are using = for comparing. = is used for assignment and not equality compassion. == is used for equality compassion. So, if((cmd1 = (-1))) and if(cmd1=(0)) should have been if((cmd1 == (-1))) and if(cmd1 == (0))
You are checking if the returned value is -1 for failure. This is incorrect. Exit code for success is 0 for failure is any value other than 0. So, if((cmd1 = (-1))) should have been if(cmd1 != 0).
How can I execute shell from a C code?
My shell is placed in /bin/sh
Following didn't seem to work for me
system("/bin/sh");
exec("/bin/sh");
Maybe you need to tell the shell it should be interactive:
system("/bin/sh -i");
However, I believe that your original system() call should have produced a shell prompt too.
Both notations (with and without the '-i') in this program give me a shell prompt (return to the previous shell by typing 'exit' and RETURN or Control-D):
#include <stdlib.h>
int main(void)
{
system("/bin/sh -i");
return 0;
}
This program works as expected for me:
int main()
{
int ret = system("/bin/sh");
printf ("Shell returned %d\n", ret);
return 0;
}
using -i causes some sort of redirection issue and everything hangs as soon as I type a command that produces output.
There are important differences between system() and exec(). system() is effectively the same as /bin/sh -c yourCommand on the command line, so the system("/bin/sh") is the same as
/bin/sh -c /bin/sh
This is why it is rarely used, because the command you want is executed by first starting an unnecessary shell process.
exec() causes the entire process image to be replaced by the command specified so if I had written:
int main()
{
int ret = exec("/bin/sh");
printf ("Shell returned %d\n", ret);
return 0;
}
The printf() and everything after it would never have been executed because the whole process transforms into an instance of /bin/sh. The proper way to run a child command is to fork and then exec in the child and wait in the parent.