[net.unix] Clunch protection

ado@elsie.UUCP (Arthur David Olson) (10/03/84)

At the top of "sh" files in the "rn" distribution this line was included:

	export PATH || (echo "You didn't use sh, you clunch." ; kill \$\$)

This was designed to ensure that if someone ran "csh" over the script
things would come to a screeching halt.

Seeing it set me to thinking...what if, instead of that line, this appeared:

	export PATH || exec sh $0

You'd get the protection without requiring the user to retype the command.

You could even go so far as to:

	( : oops >& /dev/null ) || exec sh $0

to avoid the both the generation of a diagnostic message and the possibility
of mishap if someone had created an executable program named "export".

Well friends, how about it?  Such protection might make folks lives easier.
Is it worthwhile?  Is there a better way to do it?  Mail me your responses;
if there's sufficient volume, I'll summarize them in a followup article.
--
	..decvax!seismo!elsie!ado			(301) 496-5688
	DEC, VAX and Elsie are Digital Equipment and Borden trademarks

danny@itm.UUCP (Danny) (10/08/84)

Well,

    even
        export PATH || echo "Don't use csh you clunch"

    doesn't work *every* time.  Our csh gets the "||" and "&&"
just backwards from sh.  I remember that Guy Harris (rlgvax!guy)
pointed this out once, too.  So, when I tried it out (just testing,
of course!) it failed miserably.

    Most of the time, if I point out a problem I like to include a
solution, but for this --- any takers?

                                            Danny
-- 
				Daniel S. Cox
				({gatech|akgua}!itm!danny)

guy@rlgvax.UUCP (Guy Harris) (10/13/84)

> Well,
> 
>     even
>         export PATH || echo "Don't use csh you clunch"
> 
>     doesn't work *every* time.  Our csh gets the "||" and "&&"
> just backwards from sh.  I remember that Guy Harris (rlgvax!guy)
> pointed this out once, too.  So, when I tried it out (just testing,
> of course!) it failed miserably.
> 
>     Most of the time, if I point out a problem I like to include a
> solution, but for this --- any takers?

If you've got the source to your C shell, change the line somewhere
around line 286 in "sh.sem.c" from something like

	if ((getn(value("status")) != 0) != (t->t_dtyp == TAND))

or possibly

	if ((getn(value("status")) == 0) == (t->t_dtyp == TAND))

to

	if ((getn(value("status")) == 0) != (t->t_dtyp == TAND))

which will fix the problem quite nicely.  If you don't have the source,
find out who does and pester them to fix it.  The C shell is supposed to
handle "&&" and "||" the same as the Bourne shell, and the 4.2BSD (and,
I think, 4.1BSD) versions do.  It was a bug in earlier versions.

	Guy Harris
	{seismo,ihnp4,allegra}!rlgvax!guy

gwyn@brl-tgr.ARPA (Doug Gwyn <gwyn>) (10/16/84)

#!/bin/sh
on line 1 will let the kernel exec the script using the correct shell
no matter what shell the user is running at the time.

ado@elsie.UUCP (Arthur David Olson) (10/16/84)

brl-tgr!gwyn:

> #!/bin/sh
> on line 1 will let the kernel exec the script using the correct shell
> no matter what shell the user is running at the time.

1.  The "#!/bin/sh" line lacks a space or tab between the "#!" and the
    "/bin/sh".  Quoting the second page of the exec(2) page in the UNIX
    Programmer's Manual for the Fourth Berkeley Software Distribution
    (dated 4/1/81--April Fools' Day), "The space (or tab) following the '#!'
    is mandatory."  While some implementations may not require the space, it
    behooves those of us interested in portability to use the documentation
    when trying to create portable scripts, rather than finding out what we
    can "get away with" on a particular system.

2.  The "#!" construct is not recognized on all UNIX systems.  Some may respond
    that anyone who'd continue running a system that fails to recognize "#!"
    "ougtht to" upgrade.  Alas, in the real world, there are legitimate
    economic, political, and legal reasons for staying with older versions of
    UNIX; those using older versions are ill-served by folks who would lecture
    them to upgrade rather than try to keep their needs in mind.

3.  Even if the "#!/bin/sh" line is present at the start of a shell script,
    "/bin/sh" will NOT be used to interpret the script if the script is
    executed using the command
	csh script
    (This is, at any rate, true on 4.1bsd and 4.2bsd).  "Clunch protection"
    lines are designed to guard against this possibility.  Some may respond
    that anyone who'd use the above command is a clunch; a moment's
    reflection. . .
--
UNIX is an AT&T Bell Laboratories trademark.
"sh" may be a American Librarians' Association trademark.
--
	..decvax!seismo!elsie!ado			(301) 496-5688
	DEC, VAX and Elsie are Digital Equipment and Borden trademarks

peter@rlgvax.UUCP (Peter Klosky) (10/16/84)

XXX
> ... will let the kernel exec the script using the correct shell

On our system, the kernel can't exec scripts: it only execs files 
with magic numbers.  I thought the choice of what command interpreter 
to exec to read the script was made by the shell, not by the kernel. 

guy@rlgvax.UUCP (Guy Harris) (10/17/84)

> XXX
> > ... will let the kernel exec the script using the correct shell
> 
> On our system, the kernel can't exec scripts: it only execs files 
> with magic numbers.  I thought the choice of what command interpreter
> to exec to read the script was made by the shell, not by the kernel. 

Well, that depends on which of "our" systems you're talking about.  Our
VAXes and Power 6es can exec scripts, because they're running 4.2BSD-based
OSes; the Power 5s are running a V7/S3 based OS and can't.

Dennis Ritchie came up with the notion of permitting executable files to
be executable by an arbitrary interpreter other than the CPU hardware/
microcode; the way it's done is with a magic "number" of "#!".  The
characters following the "#!" are interpreted as the path of the program
to be executed and optional arguments to that program; the path of the
file to be "executed" is given as the last argument.

This has only been implemented on Berkeley systems, to my knowledge.

	Guy Harris
	{seismo,ihnp4,allegra}!rlgvax!guy

karsh@geowhiz.UUCP (Bruce Karsh) (10/17/84)

> Dennis Ritchie came up with the notion of permitting executable files to
> be executable by an arbitrary interpreter other than the CPU hardware/
> microcode; the way it's done is with a magic "number" of "#!".  The
> characters following the "#!" are interpreted as the path of the program
> to be executed and optional arguments to that program; the path of the
> file to be "executed" is given as the last argument.
> This has only been implemented on Berkeley systems, to my knowledge.

  This has also been implemented on Masscomp systems.

gwyn@brl-tgr.ARPA (Doug Gwyn <gwyn>) (10/19/84)

> 1.  The "#!/bin/sh" line lacks a space or tab between the "#!" and the
>     "/bin/sh".
> 
> 2.  The "#!" construct is not recognized on all UNIX systems.
> 
> 3.  Even if the "#!/bin/sh" line is present at the start of a shell script,
>     "/bin/sh" will NOT be used to interpret the script if the script is
>     executed using the command
> 	csh script

1.  The documentation was wrong; white space was optional all along.
Later versions of the documentation have been corrected.  Only LOCUS
chose to force you to use white space, so far as I am aware.  By all
means stick in a space if it makes you happier.

2.  On most systems where the kernel does not understand the #! magic
number, the first line of the script will be taken as a comment and
the Bourne shell /bin/sh will be used to interpret the script anyway.
7th Edition UNIXes that never upgraded their shells may break.  Also,
systems where the Cshell was imported with insufficient care may let
the Cshell handle the script rather than either defaulting to the
native shell or examining the #! line to see what to use.

3.  Of course
	csh script
will use the wrong shell!  So will
	ed script
or many other similar commands.

4.  If one has to allow for || && vs && ||, lack of # comments, and
zillions of other variations, then immense pains are required to
produce anything close to a "portable" shell script that will either
run correctly or detect that it has been misinvoked.  The example that
started this discussion took great pains but still had loopholes; the
practicality of this approach is questionable.  It is perhaps easier
to give somebody a new shell than it is to accommodate WHATEVER he
might already have.

crp@ccivax.UUCP (Chuck Privitera) (10/19/84)

> brl-tgr!gwyn:
> 
> > #!/bin/sh
> > on line 1 will let the kernel exec the script using the correct shell
> > no matter what shell the user is running at the time.
> 
> 2.  The "#!" construct is not recognized on all UNIX systems.  Some may respond
>     that anyone who'd continue running a system that fails to recognize "#!"
>     "ougtht to" upgrade.  Alas, in the real world, there are legitimate
>     economic, political, and legal reasons for staying with older versions of
>     UNIX; those using older versions are ill-served by folks who would lecture
>     them to upgrade rather than try to keep their needs in mind.
> 

We just ran into this on our Power5's. The kernel on the Power5
doesn't understand "#!your_favorite_interpreter", and we had some
scripts that took advantage of this with #!/bin/sh.  They no longer
worked. Trivial changes to texec() in sh.exec.c of the csh solved
the problem. Similar changes could be applied to function execs()
in service.c for the Bourne shell (as is done on the VAX save that
it should read a whole line and look for #!whatever instead of
assuming '#' means use csh.)

> 3.  Even if the "#!/bin/sh" line is present at the start of a shell script,
>     "/bin/sh" will NOT be used to interpret the script if the script is
>     executed using the command
> 	csh script
>     (This is, at any rate, true on 4.1bsd and 4.2bsd).  "Clunch protection"
>     lines are designed to guard against this possibility.  Some may respond
>     that anyone who'd use the above command is a clunch; a moment's
>     reflection. . .
> --

The C-shell (and Bourne shell) on BSD systems have a primitive way
of deciding which shell to execute if the kernel doesn't get it right.
Both shells check the error returned from a failed exec and if it
is ENOEXEC (exec format error) they check the first byte of the file.
If it is a '#', BOTH shells assume that it must be a C-shell script.
Not too cool since '#' is the Bourne shell's comment character too. 
Granted you could use ':' for comments, but then you are subject
to some of the Bourne shell's features you may not intend to evoke.
(e.g. Quoting across lines) This is one reason I personally prefer
to use '#' for comments instead of ':'. Try putting this in a file
and running it:

	:
	: This is Chuck's test sh script
	:
	echo test

No output will result, because the shell is looking for a closing
"'". Whereas the following will output "test" as was intended:

	: Start with one of these to force using the Bourne shell.
	# This is Chuck's second test sh script
	#
	echo test