1

I want to create a program msh that will recognize some other C programs I wrote and spawn a new process for that C program and run it.

For example I have already written my own copy, move, and remove functions named mycopy, myremove, and mymove.

I want to be able to do ./msh mycopy file1 file2 And have msh spawn off a new process and run mycopy and perform the action, and wait for that child process to finish before exiting.

I tried what you see below and it compiles but doesn't seem to actually perform the tasks. Any suggestions? I've never used fork(), execl() or wait() before so I may have missed and include or parameter, please correct me if I'm wrong.

#include <stdio.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <string.h>

int main(int argc, char* argv[]){

int pid;

if(strcmp(argv[1], "mycopy") == 0){
    if(pid = fork() == 0){
        execl("/home/1234/mycopy", argv[2], argv[3]);
    }
}

if(strcmp(argv[1], "myremove") == 0){
    if(pid = fork() == 0){
        execl("/home/1234/myremove", argv[2]);
    }
}

if(strcmp(argv[1], "mymove") == 0){
    if(pid = fork() == 0){
        execl("/home/1234/mymove", argv[2], argv[3]);
    }
}

if(pid > 0){
    wait((int*)0);
}

return 0;
}

I tried this and working 3 printed twice. Does that mean my execl command is broken and if so how would I fix it since argv[2] and argv[3] need to be passed down to ./mycopy

    int pid = fork();
    if(strcmp(argv[1], "mycopy") == 0){
            if(pid  == 0){
                    printf("WORKING1");
                    execl("/home/1234/mycopy", argv[2], argv[3]);
                    printf("WORKING2");
            }
    }
     wait((int*)0);
    printf("WORKING3");
    return 0;
Mkey
  • 155
  • 1
  • 4
  • 12
  • You need to learn how to indent code. Also look into the function `strcmp` you cant compare strings using `==` in C – TheQAGuy Nov 19 '15 at 01:48
  • Ok I just implemented your suggestion now it seems my terminal froze. Do you see any issue with my wait command? – Mkey Nov 19 '15 at 01:52
  • 1
    Possible duplicate of [Executing a command with execvp](http://stackoverflow.com/questions/33071302/executing-a-command-with-execvp) – Petr Skocik Nov 19 '15 at 01:54
  • If your using `strcmp` you need to add `#include` – TheQAGuy Nov 19 '15 at 01:55
  • Thanks I just included that, but I'm still not having any luck getting it to work. – Mkey Nov 19 '15 at 02:03
  • 1
    I'm not sure how much you've already fixed. But the big problem in your current edit is that you need to add a NULL as the last argument in your execl() list: [How to call execl() in C with the proper arguments?](http://stackoverflow.com/questions/12596839/how-to-call-execl-in-c-with-the-proper-arguments). OTHER SUGGESTIONS: 1) Check for `argc >= 2`, 2) Add `fprintf(stderr, "I got this far\n")` debug stmts in your main and your child programs to see how far they get, 3) Add `fprintf(stderr, "pid=%d\n, pid)` debug stmts – paulsm4 Nov 19 '15 at 02:58
  • Just tried that and still nothing – Mkey Nov 19 '15 at 03:13
  • I put printf statements in all parts and they execute as expected but like you said something is wrong with my execl – Mkey Nov 19 '15 at 03:18
  • Because argv[2] and argv[3] are used in the mycopy program – Mkey Nov 19 '15 at 03:21
  • And I don't think execl takes more then 3 parameters – Mkey Nov 19 '15 at 03:21
  • 1
    `execl() ` is a "variadic" function, which means it takes as many arguments as you give it, like `printf()` does. `execl()`'s first argument is the name of the executable file to be loaded, and its *second* argument becomes the *first* argument (`argv[0]`) to the new process. – Darwin von Corax Nov 19 '15 at 03:45
  • Your edits mean some of the answers now don't make sense. Your original code didn't check the return value of `fork()` to figure out if it was in the child or parent, so the answers pointing that out are now out of sync with the question. The "question" is barely comprehensible anymore. It just has the bug with not NULL-terminating the argument list to `execl`. Read the man page. – Peter Cordes Nov 19 '15 at 05:06
  • Also, does your wrapper need to fork? Can't you *just* exec, since you simply return after `wait()`ing for the child. – Peter Cordes Nov 19 '15 at 05:10

1 Answers1

2

Forking always seems to be a bit of a mindbender for newcomers. What actually happens is that when you return from fork() you now have two processes (parent and child), both of which have just returned from fork() and both of which are about to execute the next statement.

The usual idiom is to call int child_pid = fork() and then test child_pid to determine if I am the child process (child_pid == 0) or the parent process (child_pid != 0) and carry on either exec()ing or wait()ing as appropriate.

You have not made this test; both of your processes are trying to carry out both behaviours.

That should be enough to get you on the right track.

EDIT: I just compiled the following:

/**
* @file     msh.c
* @brief    fork/execl example
*/

#include <stdio.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <string.h>

int main(int argc, char* argv[])
{

    int pid;


    if ((pid = fork()) == 0)
    {
        if(strcmp(argv[1], "mycopy") == 0)
        {
            {
                execl("./hello", "./hello", argv[2], argv[3], NULL);
            }
        }

        if(strcmp(argv[1], "myremove") == 0)
        {
            {
                execl("./hello", "./hello", argv[2], NULL);
            }
        }

        if(strcmp(argv[1], "mymove") == 0)
        {
            {
                execl("./hello", "./hello", argv[2], argv[3], NULL);
            }
        }
    }
    else
    {
        wait(NULL);
    }

    return 0;
}

(edited again) and

/**
* @file     hello.c
* @brief    test load for msh
*/

#include <stdio.h>

int main(int argc, char* argv[])
{
    int i;
    for (i = 0; i < argc; i++)
        printf("Argc[%d] = %s\n", i, argv[i]);
    return 0;
}

and it works, so perhaps the problem is in your child code?

I did notice that execl() passes its second argument as the child's argv[0], so that might be causing you problems.

Darwin von Corax
  • 5,201
  • 3
  • 17
  • 28
  • 3
    Technically `if(child_pid == 0)` we have child process. `if(child_pid > 0)` we have parent process and `if(child_pid < 0)` we have an error – TheQAGuy Nov 19 '15 at 01:54
  • Perfect I'm going to try it out now – Mkey Nov 19 '15 at 01:54
  • I've updated my original post to reflect my implementation of what you said and I'm still having no luck. – Mkey Nov 19 '15 at 02:00
  • What happens now? Try temporarily replacing your `myxxx` programs with a simple `helloWorld` just to see if you've got the forking thing working. – Darwin von Corax Nov 19 '15 at 02:05
  • 1
    `strace -f ./msh mycopy file1 file2` might help to figure out what your application actually does. But one think that is missing from fork only explanation is that exec functions only return on errors. If exec function is successful it replaces your process with the one you requested in the call. – Pauli Nieminen Nov 19 '15 at 02:05
  • So my msh process will now be overwritten with mycopy's code ? Or what exactly do you mean? I'm new to linux. I understand fork() to a point and what it's really doing, but I'm unsure of the execl – Mkey Nov 19 '15 at 02:07
  • When your process calls `exec()` it's code gets overwritten by the `exec`ed program. *This is what you want your child process to do;* it's how the newly-spawned `msh` child process "becomes" the program you actually wanted to run as the child. Like I said: mindbendy. – Darwin von Corax Nov 19 '15 at 02:10
  • I just found this in the dusty depths of my bookmarks menu: [A fork() primer](http://beej.us/guide/bgipc/output/html/multipage/fork.html "from Beej's Guide to Unix IPC") from *Beej's Big Guide to Unix Interprocess Communication*. It's a bit cursory but includes sample code. – Darwin von Corax Nov 19 '15 at 02:24
  • So I understand the fork and execl and pid checking and all that but it's still not working :'(((((( – Mkey Nov 19 '15 at 02:29
  • I updated my original post to show where i'm at. No clue why it's not working and strace was an unrecognized command on my linux box – Mkey Nov 19 '15 at 02:30
  • I replaced mycopy with a printf to see if the fork was working and it is. But when I replace the printf with execl it fails to do what it is supposed to. – Mkey Nov 19 '15 at 02:31
  • You might want to make sure that good debugging tools are installed before starting to code. My short list that I at least require to be installed: gdb, strace, ltrace, valgrind and perf. Also I like to install man pages from manpages-dev and manpages-posix-dev: [fork](http://man7.org/linux/man-pages/man2/fork.2.html), [exec](http://man7.org/linux/man-pages/man3/exec.3.html) and [wait](http://man7.org/linux/man-pages/man2/wait.2.html) – Pauli Nieminen Nov 19 '15 at 02:41
  • I'm on a school virtual box so I don't have much access to install other software. :/ – Mkey Nov 19 '15 at 02:46
  • For mycopy should it be path/./mycopy or just path/mycopy ? – Mkey Nov 19 '15 at 03:32
  • So should it be path/mycopy, NULL, argv[1], argv[2] so that mycopy argv[1] is what is supplied in the parameters – Mkey Nov 19 '15 at 03:32
  • Three solution to use missing tools in school 1) Download the source code and compile missing tools (setup prefix to be inside your home directory and use LD_LIBRARY_PATH for dynamic libraries) 2) download binary packages for your distribution and manually extract contents to your home directory (This doesn't work for all tools). 3) Ask school admins to install missing programming tools. Other are likely to need them too so it is surprising they aren't installed. – Pauli Nieminen Nov 19 '15 at 03:32
  • It should be `execl("path/to/mycopy", "path/to/mycopy", argv[1], argv[2], (char *)NULL);` so that `mycopy` gets its own name as `argv[0]`. The `NULL` argument to `execl()` is a sentinel which means "Ignore anything after this." – Darwin von Corax Nov 19 '15 at 03:36
  • Your `mycopy` code has a few issues of its own, but those are peripheral to the current conversation. I think the problem you're having now is specifically the interaction between `execl()` and `mycopy`, and the link to *Beej's Guide* I posted earlier should help with that, as should the current version of the sample code I posted. – Darwin von Corax Nov 19 '15 at 03:51