выполнить файл (execute a file)
Обоснование (Rationale)
Early proposals required that the value of argc passed to main()
be ``one or greater''. This was driven by the same requirement in
drafts of the ISO C standard. In fact, historical
implementations have passed a value of zero when no arguments are
supplied to the caller of the exec functions. This requirement
was removed from the ISO C standard and subsequently removed from
this volume of POSIX.1‐2017 as well. The wording, in particular
the use of the word should, requires a Strictly Conforming POSIX
Application to pass at least one argument to the exec function,
thus guaranteeing that argc be one or greater when invoked by
such an application. In fact, this is good practice, since many
existing applications reference argv[0] without first checking
the value of argc.
The requirement on a Strictly Conforming POSIX Application also
states that the value passed as the first argument be a filename
string associated with the process being started. Although some
existing applications pass a pathname rather than a filename
string in some circumstances, a filename string is more generally
useful, since the common usage of argv[0] is in printing
diagnostics. In some cases the filename passed is not the actual
filename of the file; for example, many implementations of the
login utility use a convention of prefixing a <hyphen-minus>
('‐'
) to the actual filename, which indicates to the command
interpreter being invoked that it is a ``login shell''.
Also, note that the test and [ utilities require specific strings
for the argv[0] argument to have deterministic behavior across
all implementations.
Historically, there have been two ways that implementations can
exec shell scripts.
One common historical implementation is that the execl(),
execv(), execle(), and execve() functions return an [ENOEXEC]
error for any file not recognizable as executable, including a
shell script. When the execlp() and execvp() functions encounter
such a file, they assume the file to be a shell script and invoke
a known command interpreter to interpret such files. This is now
required by POSIX.1‐2008. These implementations of execvp() and
execlp() only give the [ENOEXEC]
error in the rare case of a
problem with the command interpreter's executable file. Because
of these implementations, the [ENOEXEC]
error is not mentioned
for execlp() or execvp(), although implementations can still give
it.
Another way that some historical implementations handle shell
scripts is by recognizing the first two bytes of the file as the
character string "#!"
and using the remainder of the first line
of the file as the name of the command interpreter to execute.
One potential source of confusion noted by the standard
developers is over how the contents of a process image file
affect the behavior of the exec family of functions. The
following is a description of the actions taken:
1. If the process image file is a valid executable (in a format
that is executable and valid and having appropriate
privileges) for this system, then the system executes the
file.
2. If the process image file has appropriate privileges and is
in a format that is executable but not valid for this system
(such as a recognized binary for another architecture), then
this is an error and errno is set to [EINVAL]
(see later
RATIONALE on [EINVAL]
).
3. If the process image file has appropriate privileges but is
not otherwise recognized:
a. If this is a call to execlp() or execvp(), then they
invoke a command interpreter assuming that the process
image file is a shell script.
b. If this is not a call to execlp() or execvp(), then an
error occurs and errno is set to [ENOEXEC]
.
Applications that do not require to access their arguments may
use the form:
main(void)
as specified in the ISO C standard. However, the implementation
will always provide the two arguments argc and argv, even if they
are not used.
Some implementations provide a third argument to main() called
envp. This is defined as a pointer to the environment. The ISO C
standard specifies invoking main() with two arguments, so
implementations must support applications written this way. Since
this volume of POSIX.1‐2017 defines the global variable environ,
which is also provided by historical implementations and can be
used anywhere that envp could be used, there is no functional
need for the envp argument. Applications should use the getenv()
function rather than accessing the environment directly via
either envp or environ. Implementations are required to support
the two-argument calling sequence, but this does not prohibit an
implementation from supporting envp as an optional third
argument.
This volume of POSIX.1‐2017 specifies that signals set to SIG_IGN
remain set to SIG_IGN, and that the new process image inherits
the signal mask of the thread that called exec in the old process
image. This is consistent with historical implementations, and it
permits some useful functionality, such as the nohup command.
However, it should be noted that many existing applications
wrongly assume that they start with certain signals set to the
default action and/or unblocked. In particular, applications
written with a simpler signal model that does not include
blocking of signals, such as the one in the ISO C standard, may
not behave properly if invoked with some signals blocked.
Therefore, it is best not to block or ignore signals across execs
without explicit reason to do so, and especially not to block
signals across execs of arbitrary (not closely cooperating)
programs.
The exec functions always save the value of the effective user ID
and effective group ID of the process at the completion of the
exec, whether or not the set-user-ID or the set-group-ID bit of
the process image file is set.
The statement about argv[] and envp[] being constants is included
to make explicit to future writers of language bindings that
these objects are completely constant. Due to a limitation of the
ISO C standard, it is not possible to state that idea in standard
C. Specifying two levels of const-qualification for the argv[]
and envp[] parameters for the exec functions may seem to be the
natural choice, given that these functions do not modify either
the array of pointers or the characters to which the function
points, but this would disallow existing correct code. Instead,
only the array of pointers is noted as constant. The table of
assignment compatibility for dst=src derived from the ISO C
standard summarizes the compatibility:
┌────────────────────┬──────────┬────────────────┬───────────────┬─────────────────────┐
│ dst: │ char *[]
│ const char *[]
│ char *const[]
│ const char *const[]
│
├────────────────────┼──────────┼────────────────┼───────────────┼─────────────────────┤
│src:
│ │ │ │ │
│char *[]
│ VALID │ — │ VALID │ — │
│const char *[]
│ — │ VALID │ — │ VALID │
│char * const []
│ — │ — │ VALID │ — │
│const char *const[]
│ — │ — │ — │ VALID │
└────────────────────┴──────────┴────────────────┴───────────────┴─────────────────────┘
Since all existing code has a source type matching the first row,
the column that gives the most valid combinations is the third
column. The only other possibility is the fourth column, but
using it would require a cast on the argv or envp arguments. It
is unfortunate that the fourth column cannot be used, because the
declaration a non-expert would naturally use would be that in the
second row.
The ISO C standard and this volume of POSIX.1‐2017 do not
conflict on the use of environ, but some historical
implementations of environ may cause a conflict. As long as
environ is treated in the same way as an entry point (for
example, fork()), it conforms to both standards. A library can
contain fork(), but if there is a user-provided fork(), that
fork() is given precedence and no problem ensues. The situation
is similar for environ: the definition in this volume of
POSIX.1‐2017 is to be used if there is no user-provided environ
to take precedence. At least three implementations are known to
exist that solve this problem.
E2BIG
The limit {ARG_MAX} applies not just to the size of the
argument list, but to the sum of that and the size of the
environment list.
EFAULT
Some historical systems return [EFAULT]
rather than
[ENOEXEC]
when the new process image file is corrupted.
They are non-conforming.
EINVAL
This error condition was added to POSIX.1‐2008 to allow an
implementation to detect executable files generated for
different architectures, and indicate this situation to
the application. Historical implementations of shells,
execvp(), and execlp() that encounter an [ENOEXEC]
error
will execute a shell on the assumption that the file is a
shell script. This will not produce the desired effect
when the file is a valid executable for a different
architecture. An implementation may now choose to avoid
this problem by returning [EINVAL]
when a valid executable
for a different architecture is encountered. Some
historical implementations return [EINVAL]
to indicate
that the path argument contains a character with the high
order bit set. The standard developers chose to deviate
from historical practice for the following reasons:
1. The new utilization of [EINVAL]
will provide some
measure of utility to the user community.
2. Historical use of [EINVAL]
is not acceptable in
an internationalized operating environment.
ENAMETOOLONG
Since the file pathname may be constructed by taking
elements in the PATH variable and putting them together
with the filename, the [ENAMETOOLONG]
error condition
could also be reached this way.
ETXTBSY
System V returns this error when the executable file is
currently open for writing by some process. This volume of
POSIX.1‐2017 neither requires nor prohibits this behavior.
Other systems (such as System V) may return [EINTR]
from exec.
This is not addressed by this volume of POSIX.1‐2017, but
implementations may have a window between the call to exec and
the time that a signal could cause one of the exec calls to
return with [EINTR]
.
An explicit statement regarding the floating-point environment
(as defined in the <fenv.h> header) was added to make it clear
that the floating-point environment is set to its default when a
call to one of the exec functions succeeds. The requirements for
inheritance or setting to the default for other process and
thread start-up functions is covered by more generic statements
in their descriptions and can be summarized as follows:
posix_spawn (3p) 14
Set to default.
fork (3p) 14
Inherit.
pthread_create (3p) 14
Inherit.
The purpose of the fexecve() function is to enable executing a
file which has been verified to be the intended file. It is
possible to actively check the file by reading from the file
descriptor and be sure that the file is not exchanged for another
between the reading and the execution. Alternatively, a function
like openat() can be used to open a file which has been found by
reading the content of a directory using readdir().