Page MenuHomeFreeBSD

interpreter.7: Interpreter script execution
Needs ReviewPublic

Authored by temcbun_gmail.com on Apr 27 2026, 12:49 PM.
Referenced Files
Unknown Object (File)
Thu, Jun 11, 5:07 AM
Unknown Object (File)
Tue, Jun 9, 7:54 PM
Unknown Object (File)
Thu, Jun 4, 10:57 PM
Unknown Object (File)
Thu, Jun 4, 1:29 AM
Unknown Object (File)
Wed, Jun 3, 11:39 AM
Unknown Object (File)
Sun, May 24, 8:06 PM
Unknown Object (File)
Sun, May 24, 8:03 PM
Unknown Object (File)
May 18 2026, 5:29 AM
Subscribers

Details

Summary

Obtained from: OpenBSD

Diff Detail

Repository
rG FreeBSD src repository
Lint
Lint Skipped
Unit
Tests Skipped

Event Timeline

The #! mechanism is already described (more briefly) in lib/libsys/execve.2 lines 73...100. That duplication is certainly undesirable.

I don't really have an opinion whether the text in lib/libsys/execve.2 needs to be extended or moved to a new page share/man/man7/script.7.

By the way, the obscure behaviour of requiring fdescfs and making assumptions about the close-on-exec flag when using fexecve on an interpreter file remains undocumented. However, if OpenBSD doesn't document it either, this review should not add it.

share/man/man7/script.7
57–59 ↗(On Diff #176625)

Neither of the original pages (nor NetBSD, nor OpenBSD) introduce the 'shebang' term, which seems to be appropriate, since it's widely used and recognizable. If the presence of this word in the manual page itself is ok, I think we could make use of it in order to reduce the number of '#!' occurences in the whole page, since it's used too frequently. It can be substituted with 'shebang' almost in all cases.

Also, I think we can introduce the term 'shebang line' to refer to the entire line, but I'm not sure if that would be the proper term?

62 ↗(On Diff #176625)

NetBSD uses .Dq here, but OpenBSD replaced it with .Sq. I chose the .Sq variant, since in my opinion it's easier to read with the string as short as 2 characters long.

204–205 ↗(On Diff #176625)

In the original pages it runs like that:

and that the file
.Pa /tmp/script
contains:
.Bd
...
.Ed
.Pp
and that
.Pa /tmp/script
is set mode 755.

I think it can be expressed in a much simpler form.

214 ↗(On Diff #176625)

In the original pages the '$' sign is used to indicate a prompt.
Usually, in books (Absolute FreeBSD, for instance) and other sources on UNIX systems (including FreeBSD Handbook), '#' sign is used to indicate a user prompt and '%' - to indicate a super-user prompt.

Example from FreeBSD Handbook: https://docs.freebsd.org/en/books/handbook/basics/#users-superuser.

275–280 ↗(On Diff #176625)

I found this comment in sys/kern/imgact_shell.c, exec_shell_imgact():

/*
 * HISTORICAL NOTE: From 1993 to mid-2005, FreeBSD parsed out the tokens as
 * found on the first line of the script, and setup each token as a separate
 * value in arg[].  This extra processing did not match the behavior of other
 * OS's, and caused a few subtle problems.  For one, it meant the kernel was
 * deciding how those values should be parsed (wrt characters for quoting or
 * comments, etc), while the interpreter might have other rules for parsing.
 * It also meant the interpreter had no way of knowing which arguments came
 * from the first line of the shell script, and which arguments were specified
 * by the user on the command line.  That extra processing was dropped in the
 * 6.x branch on May 28, 2005 (matching __FreeBSD_version 600029).
 */

So as I understand, FreeBSD \_used\_ to pass multiple arguments to the interpreter. I think we can include this information in the HISTORY section, what do you think?

292 ↗(On Diff #176625)

The original manual page was written in 2005, I suspect that this may not be the case anymore. Shall we keep this?

345 ↗(On Diff #176625)

This is taken from the original manual page. I'm not sure what was meant by 'exec man page' here. It looks like it could be execve(2) or the 'exec family of functions' (in which case it should be exec(3)).

The #! mechanism is already described (more briefly) in lib/libsys/execve.2 lines 73...100. That duplication is certainly undesirable.

I don't really have an opinion whether the text in lib/libsys/execve.2 needs to be extended or moved to a new page share/man/man7/script.7.

Yeah, I also noticed that. However, I think, that a separate manual page would be better in this case. The page name and the section 7 make it easier for the user to find the manual page. Right now, one can only find a description of the shebang line only in case he knows that it is described in the execve(2), it's really hard to find it if you don't know where it's located. And to me, the system calls manual is not the best place for such information, since not only people doing the system call programming may be interested in this topic (they probably don't want to dive into the system call details). That's how I see it.

Both NetBSD and OpenBSD also have a description of the '#!' in execve(2). I would suggest to keep that description as brief as possible in execve(2) (just to cover the information needed for understanding the system call details) and provide a link to script(7) for a more detailed description.

Stopped there, will wait for all comments processed.

share/man/man7/script.7
38 ↗(On Diff #176625)

I dislike the name. We already have script(1). Although having identically named man pages in different sections is not wrong, it reduces the visibility.

Might be 'interpreter.7'?

41 ↗(On Diff #176625)

text have a different meaning in the context of executables. Might be use 'textual file'. or 'plain text'

46 ↗(On Diff #176625)

Define 'executable'. There you mean that it can be used to replace the executing image in the process with execve(2).

76 ↗(On Diff #176625)
83 ↗(On Diff #176625)

Since it is executed by kernel, of course PATH is not taken into account.

102 ↗(On Diff #176625)

It might be useful to read the commit message from 5f49915eb22c1fca384843198b5e174a6b325bcc.
Overall, this sentence lacks the precision.

temcbun_gmail.com marked 6 inline comments as done.
temcbun_gmail.com retitled this revision from script.7: Interpreter script execution to interpreter.7: Interpreter script execution.

Address @kib's comments:

  • Rename script.7 -> interpreter.7.
  • Change 'text file' -> 'plain text file'.
  • Make the sentece about 'executable program' more precise.
  • Instead of trying to explain how execve(2) passes arguments to argv using multiple separate sentences, adopt a table-like comment description found in sys/kern/imgact_shell.c.

I recommend you to read the latest fexecve(2) man page, where it discusses /dev/fd in relation to the scripts.

The 'interpreter' name for the page is good, but of course there is further confusion with it, because ELF binary format also has the use for the term. I suggest to add a note somewhere very close to beginning, to shortly point out that this is man page about interpreter for scripts, not interpreter for ELF AKA dynamic linker ld-elf.so.1(1).

share/man/man7/interpreter.7
41
100

This is confusing. These are argv[x+1] argv[x+2]... i.e. the arguments passed by execve are not glued into single arg, instead the argv[0] 1 2 are inserted as appropriate.

119

Perhaps it is useful to show the current value for the constant. May be even reverse, ie. specify the value inline, and then make a note that the value is available as MAXINTERP symbol for C programs.

125

s/may/must/ ?

132
187

I suggest you to look at bin/sh/exec.c, in particular, to the isbinary() function, to see how our /bin/sh somewhat restricts which noexec files are attempted to be interpreted as shell scripts.

376

All this CAVEATS section is somewhat pointless since FreeBSD does not support suid scripts.