Hi Terry,

> Bob Dunlop wrote:
> >     exec rdate -v 192.168.0.2
>
> This only occurred to me last night.  When I put the command into my
> script without preceding it with 'exec' it appears to work.  According
> to the references I've found for exec, (including its man page), the
> command allows you to wrap the arguments of the target command so that
> the underlying code receives them correctly.

I don't recognise that description.  :-)  Which man page?  On my system,
there's

    $ man -f exec | sort -V
    exec (1p)            - execute commands and open, close, or copy file...
    exec (3p)            - execute a file
    exec (3)             - execute a file
    exec (n)             - Invoke subprocesses
    $ 

But yours could be different.   The first line of `man exec' will give
the section name in parenthesis.

> My rdate command includes one switch and one argument, so how come it
> works without the exec prefix?

You're so off track that I'll ignore the question.  :-)

If you've a three-command shell script that does

    #! /bin/sh

    who -b
    id -G
    date -d yesterday +%Y-%m-%d

then when sh is told to run it, it reads in the file.  That's a single
Linux process doing that work.  There is no way for a process to ask the
kernel to create a new process to run who(1), say.  Instead, there are
two distinct system calls that sh uses to get the kernel to run who.
(This was a fundamental distinction between Unix and many other OS at
the time that gave Unix some of its unique attributes that made it
popular.)

First, sh uses fork(2) to have the kernel duplicate it.  There are now
two sh processes running: the original that made the request to the
kernel; and the "child" of it that has been created.  The first still
has its original process ID, the second has a new one that wasn't
already in use.  The return value from fork() in the parent is the
child's process ID so it can distinguish it from other children, e.g. to
kill(2) it.  But the same call to fork() also returns in the child and
that return value is 0;  an invalid PID.

This allows the source code to do alternate things in the parent and
child.

    pid = fork();
    if (pid == -1)
        err(1, "fork failed");
    if (pid)
        return;
    /* Only the child continues from here. */

That's the first half of the story.  sh can now create many sh, each of
which can create yet more.  But for running the script, the child will
use the execve(2) system call to execute the given file, passing on the
specified arguments and environment variables, in this case
/usr/bin/who.  The kernel keeps the child sh's process ID, and quite a
few other bits of it like open files, but replaces the running machine
code with that from who, arranging for execution to wind its way towards
main().

Meanwhile, parent sh will use the wait(2) system call to go to sleep
until the kernel returns to it with news of its child, e.g. that it has
_exit(2)'d.  sh starts all over again with the next line for id(1) and
the fork, execve, wait cycle repeats.

In the sh's language, placing "exec" at the start of the command is
telling sh to skip the fork stage.  It still calls execve(), but the
kernel isn't replacing the child shell;  it's the original shell that
gets trampled with a new executable.  If the above script has the second
command changed to "exec id -G" then when id(1) finishes and _exit()s,
it's the parent of the sh that was running the script that returns from
wait() with news that its child, that it started as a sh but ended up as
id, has exited.  Thus date(1) isn't run.

A minor optimisation, still useful on small machines, is to therefore
augment the last command a shell script runs, if it's an external one
requiring a fork+exec, with exec, saving the fork and its overhead of
creating a new process.  That's why Bob said to replace

    rdate ...
    exit $?

with

    exec rdate ...

Cheers, Ralph.

-- 
Next meeting:  Bournemouth, Tuesday, 2017-10-03 20:00
Meets, Mailing list, IRC, LinkedIn, ...  http://dorset.lug.org.uk/
New thread:  mailto:dorset@mailman.lug.org.uk / CHECK IF YOU'RE REPLYING
Reporting bugs well:  http://goo.gl/4Xue     / TO THE LIST OR THE AUTHOR

Reply via email to