Originální popis anglicky:
system - issue a command
Návod, kniha: POSIX Programmer's Manual
#include <stdlib.h>
int system(const char *
command);
If
command is a null pointer, the
system() function shall
determine whether the host environment has a command processor. If
command is not a null pointer, the
system() function shall pass
the string pointed to by
command to that command processor to be
executed in an implementation-defined manner; this might then cause the
program calling
system() to behave in a non-conforming manner or to
terminate.
The environment of the executed command shall be as if a child process were
created using
fork(), and the child process invoked the
sh
utility using
execl() as follows:
execl(<shell path>, "sh", "-c", command, (char *)0);
where <
shell path> is an unspecified pathname for the
sh
utility.
The
system() function shall ignore the SIGINT and SIGQUIT signals, and
shall block the SIGCHLD signal, while waiting for the command to terminate. If
this might cause the application to miss a signal that would have killed it,
then the application should examine the return value from
system() and
take whatever action is appropriate to the application if the command
terminated due to receipt of a signal.
The
system() function shall not affect the termination status of any
child of the calling processes other than the process or processes it itself
creates.
The
system() function shall not return until the child process has
terminated.
If
command is a null pointer,
system() shall return non-zero to
indicate that a command processor is available, or zero if none is available.
The
system() function shall always return non-zero when
command
is NULL.
If
command is not a null pointer,
system() shall return the
termination status of the command language interpreter in the format specified
by
waitpid(). The termination status shall be as defined for the
sh utility; otherwise, the termination status is unspecified. If some
error prevents the command language interpreter from executing after the child
process is created, the return value from
system() shall be as if the
command language interpreter had terminated using
exit(127) or
_exit(127). If a child process cannot be created, or if the termination
status for the command language interpreter cannot be obtained,
system() shall return -1 and set
errno to indicate the error.
The
system() function may set
errno values as described by
fork() .
In addition,
system() may fail if:
- ECHILD
- The status of the child process created by system()
is no longer available.
The following sections are informative.
None.
If the return value of
system() is not -1, its value can be decoded
through the use of the macros described in
<sys/wait.h>. For
convenience, these macros are also provided in
<stdlib.h>.
Note that, while
system() must ignore SIGINT and SIGQUIT and block
SIGCHLD while waiting for the child to terminate, the handling of signals in
the executed command is as specified by
fork() and
exec. For
example, if SIGINT is being caught or is set to SIG_DFL when
system()
is called, then the child is started with SIGINT handling set to SIG_DFL.
Ignoring SIGINT and SIGQUIT in the parent process prevents coordination problems
(two processes reading from the same terminal, for example) when the executed
command ignores or catches one of the signals. It is also usually the correct
action when the user has given a command to the application to be executed
synchronously (as in the
'!' command in many interactive applications).
In either case, the signal should be delivered only to the child process, not
to the application itself. There is one situation where ignoring the signals
might have less than the desired effect. This is when the application uses
system() to perform some task invisible to the user. If the user typed
the interrupt character (
"^C" , for example) while
system() is being used in this way, one would expect the application to
be killed, but only the executed command is killed. Applications that use
system() in this way should carefully check the return status from
system() to see if the executed command was successful, and should take
appropriate action when the command fails.
Blocking SIGCHLD while waiting for the child to terminate prevents the
application from catching the signal and obtaining status from
system()'s child process before
system() can get the status
itself.
The context in which the utility is ultimately executed may differ from that in
which
system() was called. For example, file descriptors that have the
FD_CLOEXEC flag set are closed, and the process ID and parent process ID are
different. Also, if the executed utility changes its environment variables or
its current working directory, that change is not reflected in the caller's
context.
There is no defined way for an application to find the specific path for the
shell. However,
confstr() can provide a value for
PATH that is
guaranteed to find the
sh utility.
The
system() function should not be used by programs that have set user
(or group) ID privileges. The
fork() and
exec family of
functions (except
execlp() and
execvp()), should be used
instead. This prevents any unforeseen manipulation of the environment of the
user that could cause execution of commands not anticipated by the calling
program.
There are three levels of specification for the
system() function. The
ISO C standard gives the most basic. It requires that the function
exists, and defines a way for an application to query whether a command
language interpreter exists. It says nothing about the command language or the
environment in which the command is interpreted.
IEEE Std 1003.1-2001 places additional restrictions on
system(). It requires that if there is a command language interpreter,
the environment must be as specified by
fork() and
exec. This
ensures, for example, that close-on-
exec works, that file locks are
not inherited, and that the process ID is different. It also specifies the
return value from
system() when the command line can be run, thus
giving the application some information about the command's completion status.
Finally, IEEE Std 1003.1-2001 requires the command to be
interpreted as in the shell command language defined in the Shell and
Utilities volume of IEEE Std 1003.1-2001.
Note that,
system(NULL) is required to return non-zero, indicating that
there is a command language interpreter. At first glance, this would seem to
conflict with the ISO C standard which allows
system(NULL) to
return zero. There is no conflict, however. A system must have a command
language interpreter, and is non-conforming if none is present. It is
therefore permissible for the
system() function on such a system to
implement the behavior specified by the ISO C standard as long as it is
understood that the implementation does not conform to
IEEE Std 1003.1-2001 if
system(NULL) returns zero.
It was explicitly decided that when
command is NULL,
system()
should not be required to check to make sure that the command language
interpreter actually exists with the correct mode, that there are enough
processes to execute it, and so on. The call
system(NULL) could,
theoretically, check for such problems as too many existing child processes,
and return zero. However, it would be inappropriate to return zero due to such
a (presumably) transient condition. If some condition exists that is not under
the control of this application and that would cause any
system() call
to fail, that system has been rendered non-conforming.
Early drafts required, or allowed,
system() to return with
errno
set to [EINTR] if it was interrupted with a signal. This error return was
removed, and a requirement that
system() not return until the child has
terminated was added. This means that if a
waitpid() call in
system() exits with
errno set to [EINTR],
system() must
reissue the
waitpid(). This change was made for two reasons:
- 1.
- There is no way for an application to clean up if
system() returns [EINTR], short of calling wait(), and that
could have the undesirable effect of returning the status of children
other than the one started by system().
- 2.
- While it might require a change in some historical
implementations, those implementations already have to be changed because
they use wait() instead of waitpid().
Note that if the application is catching SIGCHLD signals, it will receive such a
signal before a successful
system() call returns.
To conform to IEEE Std 1003.1-2001,
system() must use
waitpid(), or some similar function, instead of
wait().
The following code sample illustrates how
system() might be implemented
on an implementation conforming to IEEE Std 1003.1-2001.
#include <signal.h>
int system(const char *cmd)
{
int stat;
pid_t pid;
struct sigaction sa, savintr, savequit;
sigset_t saveblock;
if (cmd == NULL)
return(1);
sa.sa_handler = SIG_IGN;
sigemptyset(&sa.sa_mask);
sa.sa_flags = 0;
sigemptyset(&savintr.sa_mask);
sigemptyset(&savequit.sa_mask);
sigaction(SIGINT, &sa, &savintr);
sigaction(SIGQUIT, &sa, &savequit);
sigaddset(&sa.sa_mask, SIGCHLD);
sigprocmask(SIG_BLOCK, &sa.sa_mask, &saveblock);
if ((pid = fork()) == 0) {
sigaction(SIGINT, &savintr, (struct sigaction *)0);
sigaction(SIGQUIT, &savequit, (struct sigaction *)0);
sigprocmask(SIG_SETMASK, &saveblock, (sigset_t *)0);
execl("/bin/sh", "sh", "-c", cmd, (char *)0);
_exit(127);
}
if (pid == -1) {
stat = -1; /* errno comes from fork() */
} else {
while (waitpid(pid, &stat, 0) == -1) {
if (errno != EINTR){
stat = -1;
break;
}
}
}
sigaction(SIGINT, &savintr, (struct sigaction *)0);
sigaction(SIGQUIT, &savequit, (struct sigaction *)0);
sigprocmask(SIG_SETMASK, &saveblock, (sigset_t *)0);
return(stat);
}
Note that, while a particular implementation of
system() (such as the one
above) can assume a particular path for the shell, such a path is not
necessarily valid on another system. The above example is not portable, and is
not intended to be.
One reviewer suggested that an implementation of
system() might want to
use an environment variable such as
SHELL to determine which command
interpreter to use. The supposed implementation would use the default command
interpreter if the one specified by the environment variable was not
available. This would allow a user, when using an application that prompts for
command lines to be processed using
system(), to specify a different
command interpreter. Such an implementation is discouraged. If the alternate
command interpreter did not follow the command line syntax specified in the
Shell and Utilities volume of IEEE Std 1003.1-2001, then
changing
SHELL would render
system() non-conforming. This would
affect applications that expected the specified behavior from
system(),
and since the Shell and Utilities volume of IEEE Std 1003.1-2001
does not mention that
SHELL affects
system(), the application
would not know that it needed to unset
SHELL .
None.
exec() ,
pipe() ,
waitpid() , the Base Definitions volume
of IEEE Std 1003.1-2001,
<limits.h>,
<signal.h>,
<stdlib.h>,
<sys/wait.h>,
the Shell and Utilities volume of IEEE Std 1003.1-2001,
sh
Portions of this text are reprinted and reproduced in electronic form from IEEE
Std 1003.1, 2003 Edition, Standard for Information Technology -- Portable
Operating System Interface (POSIX), The Open Group Base Specifications Issue
6, Copyright (C) 2001-2003 by the Institute of Electrical and Electronics
Engineers, Inc and The Open Group. In the event of any discrepancy between
this version and the original IEEE and The Open Group Standard, the original
IEEE and The Open Group Standard is the referee document. The original
Standard can be obtained online at http://www.opengroup.org/unix/online.html
.