After a long time of researching for my problem, I have really no idea how I can solve it.
My question is that I need the C source code for something like this:
ls &
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/wait.h>
int main(void) {
int new_pid;
int status;
new_pid = fork();
if (new_pid == 0) {
execlp("ls", "ls", "-l", NULL);
} else {
waitpid(new_pid, &status, 0);
}
return 0;
}
If I code it like this, 'ls -l' will be executed, but it wasnt forked to the background.
It is just an example 'ls -l', it could also be 'xournal &;', 'libreoffice &' or something like this.
My main problem is that I have no idea how to code '&' in C.
Can anyone please provide me a tip or even a solution for this?
When you execute another program, you need to call these functions:
new_pid = fork();
exec(...); //in the child only
If you want to wait until that new process ends (i.e. not specifying the & ) you call
waitpid(new_pid, ...);
That way, your shell blocks until the process you launced is finished.
If you don't want to wait, but just continue operating your shell (i.e. specifying the &) you simply do not call waitpid().
Use system("ls &").
It'd help if you explained why you wanted to run something in the background.
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 using a given md5 function who calculates a file hash when you feed it with a file address. Thing is that i need to execute this program using fork() and then load it using any exe...() function(im trying with execlp()) but when i do it and i pass the single argument i need to calculate the hash it fails. I tried running md5 program manually with the exact argument i use in execlp and it doesn't fail so i'm just assuming it must be something wrong with execlp parameters. Here's an example i made to explain the scenario:
#include <stdio.h>
#include <sys/types.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/wait.h>
int main(){
pid_t cpid;int status;
cpid = fork();
if(cpid < 0){
printf("Error fork\n");
exit (EXIT_FAILURE);
}else if (!cpid){
if (execlp("./hashMD5/me/md5","md5","testfile.a",(char*)NULL) == -1){
printf("Error: Loading process\n");
exit(EXIT_FAILURE);
}
}else{
waitpid(cpid,&status,0);
}
exit (EXIT_SUCCESS);
}
when i use this i got an error in terminal:
$testfile.a can't be opened
but if i manually execute the md5 program with the exactly same argument i got the correct execution.
What's wrong? Help!
the following proposed code:
cleanly compiles
documents why each header file is included
uses a proper call to execl() rather than execlp() because execl() expects the first parameter to be a complete path while execlp() expects the first parameter to be just a file name.
properly formats the code, for ease of readability and understanding
properly handles calling execl() and possible failure of that call
properly passes error messages to stderr rather than stdout, using perror(), so the reason the system thinks the error occurred is also displayed on stderr.
And now, the proposed code:
#include <stdio.h> // perror()
#include <sys/types.h>
#include <stdlib.h> // exit(), EXIT_FAILURE, EXIT_SUCCESS
#include <unistd.h> // fork(), execlp()
#include <sys/wait.h> // waitpid()
int main( void )
{
pid_t cpid;int status;
cpid = fork();
if(cpid < 0)
{ // error
perror("Error fork\n");
exit (EXIT_FAILURE);
}
else if (!cpid)
{ // child
execl("./hashMD5/me/md5","md5","testfile.a", NULL);
perror("Error: Loading process\n");
exit(EXIT_FAILURE);
}
else
{ // parent
waitpid(cpid,&status,0);
}
exit (EXIT_SUCCESS);
}
I finally solved the problem. I appreciate the improvements people gave me, i'm always happy to learn new things!
The problem was with the argument itself: Even when you use execlp to create a brand new process the path of the argument remains relative to parent process, that's why was not working. After several headaches i finally realized that. Thanks to everyone!
I'm not familiar with C at all.
How do I start a child process? This child process is going to execute the specified command with a call to execve(). It will try to search among the file directory specified in the environment variable PATH after the command can be
found as executable file.
I've done this so far:
//Do commands
pid_t childId;
// Fork the child process
child_id = safefork.c(); //can't use fork();
safefork.c
Code provided by the tutor; do not damn the messenger!
#include <stdlib.h>
#include <sys/types.h>
#include <unistd.h>
#include <sys/errno.h>
extern int errno;
#define MAX_PROCESSES 6
static int n_processes(void)
{
return system("exit `/bin/ps | /store/bin/wc -l`")/256;
}
pid_t safefork(void)
{
static int n_initial = -1;
if (n_initial == -1) /* Første gang funksjonen kalles: */
n_initial = n_processes();
else if (n_processes() >= n_initial+MAX_PROCESSES) {
sleep(2);
errno = EAGAIN;
return (pid_t)-1;
}
return fork();
}
Fixing your code
In your code, get the name of the variable spelled consistently (child_id is not the same as childId).
pid_t child_id = simplefork();
if (child_id < 0)
{
...handle error...
}
else if (child_id == 0)
{
...do childish code - execve() etc...
}
else
{
...do parental code - waitpid() etc...
}
Note that the fork() call within the simplefork() function that you're given to use is responsible for creating the new process. That's all it takes; that's the way it's done for all processes except the very first process.
Why not fork()?
What do you mean by "can't use fork()"? The main alternative mechanism is vfork(), which is a very restricted variant of fork() (do not use it); or maybe you could use posix_spawn() or posix_spawnp() — which are incredibly complex alternatives. I don't think there are any other options.
After forking, you might be able to use execvp() instead of execve() — it will do the path search for you. Unless, of course, the purpose of the exercise is to implement execvp() in terms of execve().
Your code uses the notation safefork.c(), but that is not usually correct in C; I could devise a structure type that would make it work, but it probably isn't what you meant.
We got another file called safefork.c — we are not allowed to use fork, only safefork which is already given.
[…before the code was posted]
OK; that's very curious. Presumably, you got a header safefork.h which declares whatever function you're supposed to use (perhaps extern pid_t safefork(void);), and the file safefork.c which does something to wrap around fork(). 'Tis odd: I don't think fork() is a dangerous function. I'd be curious to see what the 'safe fork' does, but I'm sceptical that it is significantly safer than the standard fork function. (I suppose it could does some things like fflush(0) before invoking fork(), or do an error exit if the fork() fails, but that's pushing the envelope.)
[…after the code was posted]
A critique of the code for safefork(), which I fully recognize is not your own code but code that is given to you to use.
The code for safefork() is an abomination. It runs a shell via system() which runs ps and wc to find out how many processes you currently have running, and goes to sleep for 2 seconds if you can't do the fork() because there are too many processes running (more than 6, maybe including the 3 that the safefork() is running!) and then returns "I failed". Someone needs their head seeing to (and no, that isn't you; it is the author of the code).
Oh, and extern int errno; is incorrect; the only safe way to declare errno is by #include <errno.h>. Negative marks to the teacher for that blunder. It is not a good idea to #include <sys/errno.h>; #include <sys/types.h> is not often needed in modern POSIX — from POSIX 2008 onwards at any rate; it may have been unnecessary before that). In the context of the safefork.h header, making it self-contained does require #include <sys/types.h>.
Even assuming that safefork() is a good idea (it isn't), it should be implemented as shown below.
safefork.h
#ifndef SAFEFORK_H_INCLUDED
#define SAFEFORK_H_INCLUDED
#include <sys/types.h> // pid_t
extern pid_t safefork(void);
#endif
safefork.c
#include "safefork.h"
#include <errno.h>
#include <stdlib.h>
#include <unistd.h>
#define MAX_PROCESSES 6
static int n_processes(void)
{
return system("exit `/bin/ps | /store/bin/wc -l`") / 256;
}
pid_t safefork(void)
{
static int n_initial = -1;
if (n_initial == -1)
n_initial = n_processes();
else if (n_processes() >= n_initial+MAX_PROCESSES)
{
errno = EAGAIN;
return (pid_t)-1;
}
return fork();
}
I am trying to learn how to use the pipe() command in C, and trying to create a test program to duplicate the functionality of ls | grep ".c", if I were to enter this into a linux terminal. If I enter this into the terminal, I only get test.c as a result.
My code is as follows:
#include "stdio.h"
#include "stdlib.h"
#include "unistd.h"
#include "fcntl.h"
int main(int argc, char** argv)
{
int pipefd[2];
int childpid,childpid2;
char* cmd[3]={"ls",NULL,NULL};
char* cmd2[3]={"grep",".c",NULL};
pipe(pipefd);
if(childpid=fork()){
//parent
}else{
//child
//write
close(pipefd[0]);
dup2(pipefd[1],STDOUT_FILENO);
execvp("ls", cmd);
}
if(childpid2=fork()){
}
else{
close(pipefd[1]);
dup2(pipefd[0],STDIN_FILENO);
execvp("grep",cmd2);
}
close(pipefd[0]);
close(pipefd[1]);
return 0;
}
This code returns me the following results ($ is the terminal prompt):
$a.out
$test.c
(blank line)
The program doesn't complete, but hangs until I quit it. What problems do I have? How can I mimic the terminal? I'm new to C, and using a premade template of a program, so forgive me if there are glaring mistakes.
Try this:
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <fcntl.h>
int main(int argc, char** argv)
{
int pipefd[2];
int childpid,childpid2;
char* cmd[3]={"ls",NULL,NULL};
char* cmd2[3]={"grep",".c",NULL};
pipe(pipefd);
if(childpid=fork()){
//parent
close(pipefd[1]);
dup2(pipefd[0],STDIN_FILENO);
execvp("grep",cmd2);
}else{
//child
//write
close(pipefd[0]);
dup2(pipefd[1],STDOUT_FILENO);
execvp("ls", cmd);
}
return 0;
}
Actually the program exits right away — in fact, the parent process exits before the children run, which is why there's a shell prompt before "test.c".
You can improve things a bit by adding this in your parent:
wait(childpid);
wait(childpid2);
which will make the parent exit after both children.
Your program quits immediately, while your processes run in the background. They overwrite the prompt, and makes you think the program is still running even though the shell is waiting for your input (press enter or type a command blindly and see.
You only see test.c because that's the only matching file in your directory (also note that you're checking for "filenames containing c anywhere except the first character", not "ending in .c" which would be grep '\.c$').
The simple fix is to add:
wait(NULL); wait(NULL);
right before your return 0.
This question is a bit old, but here's an older answer that was never provided. Use libpipeline. libpipeline is a pipeline manipulation library. The use case is one of the man page maintainers who had to frequently use a command like the following (and work around associated OS bugs):
zsoelim < input-file | tbl | nroff -mandoc -Tutf8
Here's the libpipeline way:
pipeline *p;
int status;
p = pipeline_new ();
pipeline_want_infile (p, "input-file");
pipeline_command_args (p, "zsoelim", NULL);
pipeline_command_args (p, "tbl", NULL);
pipeline_command_args (p, "nroff", "-mandoc", "-Tutf8", NULL);
status = pipeline_run (p);
The libpipeline has more examples on its homepage. The library is also included in many distros, including Arch, Debian, Fedora, Linux from Scratch and Ubuntu.
How can I implement chmod command on file by using exec? I would appreciate if anyone can provide me a code.
I'm not going to show you a working model, but execve() works like this:
char *args[] = {"foo", "argument1", "argument2", (char *)NULL};
... handle forking ....
res = execve("/sbin/foo", args, (char *)NULL);
... handle execve() failing ....
The third argument to execve() is left as an exercise for the reader to research, NULL may or may not be suitable for your assignment. Additionally, its up to you to determine what type res should be and what it should equal on success. Notice casting NULL.
The single UNIX specification is usually a good place to start.
From C code, directly calling chmod(2) will almost certainly be a better choice than going through the whole hassle of fork()ing and exec()ing.
Admittedly, most of that hassle is the fork() part, and if your program does not need to do anything else after the exec() call, then just running one of the exec() family functions without forking is reasonably fine (for an exercise in using exec(), that is).
try this: http://support.sas.com/documentation/onlinedoc/sasc/doc/lr2/execve.htm
also see: http://linux.about.com/library/cmd/blcmdl3_execvp.htm
#include <sys/types.h>
#include <unistd.h>
#include <stdio.h>
main()
{
pid_t pid;
char *parmList[] = {"/bin/chmod", "0700", "/home/op/biaoaai/bead",NULL};
if ((pid = fork()) ==-1) //fork failed
perror("fork error");
else if (pid == 0) { //child (pid==0 if child)
execvp("chmod", parmList);
printf("Return not expected. Must be an execve error.n");
} else { //parent (pid==child process)
//parent specific code goes here
}
}
Edit: I never actually compiled... updated with users working paramList.