1

I would like to start a new process from each of my child process and have them do addition of numbers passed as parameters through exec(). Something like this. I just don't know how I can access the parameters in the new process.

code.c

#include <stdio.h>
#include <stdlib.h>
# include <unistd.h>
# include <sys/types.h>
# include <sys/stat.h>
# include <time.h>
# include <stdlib.h>
# include <dirent.h>
# include <stdio.h>
# include <string.h>
# include <getopt.h>
# include<stdbool.h>
# include <ctype.h>
# include<sys/wait.h>
# include<signal.h>
# include <sys/mman.h>
# include<sys/time.h>

void forking()
{ int a=4,b=5
for (int i=0;i<4;i++)
pid_t pID = fork();

                   if (pID == 0)  
                   {
                    static char *argv[]={a,b,NULL};
                                    execv("/EXEC.c",argv);
                   } 
                   else
                     wait(pID);

}

void main(int argc, char **argv)
{
    forking();
}

EXEC.c

#include <stdio.h>
#include <stdlib.h>
# include <stdio.h>
# include <string.h>
int main()
{
    //Code to add a and b and print the sum
    printf("%d",a+b);
}
Jonathan Leffler
  • 730,956
  • 141
  • 904
  • 1,278
Fairy
  • 101
  • 2
  • 12
  • 1
    You should not be writing `/EXEC.c` in (a) the root directory (don't write in the root directory — don't run as root, because only root should be able to write in the root directory, and running as root is risky and should be avoided), and (b) don't call your executable programs with names that look like source code (`EXEC.c` would normally be a C source file, not a program that can be executed; you need to create and run `EXEC` from `EXEC.c`). Some would add "don't shout" — most often, program names are all lower-case, or mostly lower-case; they are rarely mostly upper-case as shown. – Jonathan Leffler Sep 30 '19 at 03:55
  • In this case, compiling `exec.c` to create `exec` would work badly because `exec` is a built-in shell command that is not searched for on disk. Using `/path/to/exec` (or even `./exec`) would work, but the path would be necessary. Use a different name (don't use `test` for your programs either — that's another shell built-in). – Jonathan Leffler Sep 30 '19 at 03:58
  • Ok i will change to exec instead of EXEC.c But my main question is, how can I pass a and b in new process (exec.c here) . I'm pretty sure what I've written is wrong – Fairy Sep 30 '19 at 04:00
  • See [What should `main()` return in C and C++](https://stackoverflow.com/questions/204476/) — you should be using `int main(void)` or `int main(int argc, char **argv)`. You access arguments passed to your program via `argc` and `argv` — they are strings. You pass arguments to executed programs as strings, not as plain integers as you are trying to do with `static char *argv[]={a,b,NULL};` (where `a` and `b` are of type `int`). You should pass the program name as `argv[0]`, and the operational arguments as `argv[1]` and `argv[2]` — you're correct to add NULL to the end of the argument list. – Jonathan Leffler Sep 30 '19 at 04:35
  • You shouldn't include all the headers you can think of in `code.c` — you should include only those you use. You shouldn't repeat `` or `stdlib.h>`. You should be consistent in your spacing — preferably following the pattern of your first `#include ` line (no space between `#` and `include`; one space between `include` and ``; no trailing white space usually, though a comment is allowed if deemed beneficial and that should be preceded by white space). And the `printf()` in `EXEC.c` should have a newline at the end of the format string. – Jonathan Leffler Sep 30 '19 at 04:38

1 Answers1

4

There are many, many problems in the code shown:

  • It doesn't compile.
  • You should not be writing /EXEC.c in the root directory.

    • Don't write in the root directory.
    • Don't run as root.
    • Only root should be able to write in the root directory.
    • Running as root is risky and should be avoided.
  • Don't call your executable programs with names that look like source code — EXEC.c would normally be a C source file, not a program that can be executed; you need to create and run EXEC from EXEC.c.
  • Some would add "don't shout" — most often, program names are all lower-case, or mostly lower-case; they are rarely mostly upper-case as shown.
  • In this case, compiling exec.c to create exec would work badly OK because even though exec is a built-in shell command that is not searched for on disk. Using /path/to/exec (or even ./exec) would work, but some path (at least one /) would be necessary. Because you use execv(), the kernel (not the shell) would execute the program directly. However, you should still use a different name — there is scope for confusion.
  • Don't use test as a name for your programs either — that's another shell built-in, and calling your own program test leads to confusion sooner or later, usually sooner.
  • See What should main() return in C and C++ — you should be using int main(void) or int main(int argc, char **argv) (interestingly, you should be using the shorter variant in code.c and the longer in EXEC.c, but you have them backwards).
  • You access arguments passed to your program via argc and argv — the arguments are strings.
  • You pass arguments to executed programs as strings, not as plain integers as you are trying to do with static char *argv[]={a,b,NULL}; (where a and b are of type int). You should be getting compiler warnings if not errors from this.
  • You should pass the program name as argv[0], and the operational arguments as argv[1] and argv[2] — you're correct to add NULL to the end of the argument list.
  • You shouldn't include all the headers you can think of in code.c — you should include only those you use.
  • You shouldn't repeat <stdio.h> or <stdlib.h>.
  • You should be consistent in your spacing — preferably following the pattern of your first #include <stdio.h> line (no space between # and include; one space between include and <stdio.h>; no trailing white space usually, though a comment is allowed if deemed beneficial and that should be preceded by white space).
  • The printf() in EXEC.c should have a newline at the end of the format string.
  • The code in forking() doesn't compile because the body of the for loop is pid_t pID = fork(); — and you can't have a variable definition as the body of a loop without surrounding braces. Also, pID would not be defined for the if statement unless that is also in the body of the loop. Also, the definitions of a and b are not finished with a semicolon.
  • You should have an exit() of some sort after execv(), preferably with an error message too, just in case the execv() fails.
  • The call to wait() is faulty — wait() expects an int pointer argument, not a plain int.

There may be other issues as well that get fixed in passing. The revised code below is two files, parent.c and child.c. The code assumes that the child program is in the current directory (so ./child will execute it). You run parent; it creates the child processes.

parent.c

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/wait.h>

static void forking(void)
{
    for (int i = 0; i < 4; i++)
    {
        pid_t pID = fork();

        if (pID == 0)
        {
            static char *args[] = { "./child", "4", "5", NULL };
            execv(args[0], args);
            fprintf(stderr, "Failed to execute %s\n", args[0]);
            exit(EXIT_FAILURE);
        }
        else if (pID < 0)
        {
            fprintf(stderr, "Failed to fork()\n");
            exit(EXIT_FAILURE);
        }
        else
        {
            int corpse;
            int status;
            while ((corpse = wait(&status)) > 0)
            {
                printf("Process %d exited with status 0x%.4X\n", corpse, status);
                if (corpse == pID)
                    break;
            }
        }
    }
}

int main(void)
{
    forking();
    return 0;
}

child.c

#include <stdio.h>
#include <stdlib.h>

int main(int argc, char **argv)
{
    if (argc != 3)
    {
        fprintf(stderr, "Usage: %s number1 number2\n", argv[0]);
        exit(EXIT_FAILURE);
    }
    long number1 = strtol(argv[1], 0, 0);
    long number2 = strtol(argv[2], 0, 0);
    printf("%ld\n", number1 + number2);
    return 0;
}

Strictly, the code should check that strtol() worked, but doing so properly is fiddly — see Correct usage of strtol()? for more details.

Sample output

$ ./parent
9
Process 14201 exited with status 0x0000
9
Process 14202 exited with status 0x0000
9
Process 14203 exited with status 0x0000
9
Process 14204 exited with status 0x0000
$
Jonathan Leffler
  • 730,956
  • 141
  • 904
  • 1,278
  • One question: How can I send a char pointer to child.c Basically I have this shared memory between children and parent and I want the new process child.c to also have access to this. – Fairy Oct 01 '19 at 15:41
  • When you exec, the new process has no access to shared memory (or any other memory) from the old process. (Merely forking does not lose access to shared memory in the child; however, the child has its own copy of all other memory.) So, using shared memory, the `child` process would have to reconnect to the shared memory and know where to look for the data in the shared memory, possibly via its argument list, or perhaps some other mechanism. It won’t be trivial. – Jonathan Leffler Oct 01 '19 at 15:52