Re: Bug in #! processing (long reply)

From: Garance A Drosihn <drosih_at_rpi.edu>
Date: Mon, 31 Jan 2005 23:09:19 -0500
Way back on Oct 02, 2004, David G. Lawrence wrote:
>Garance wrote:
>  > In fact, it seems to be the '--' which is causing the rest of the
>>  line to be ignored, not the '#'.
>>
>>  The PR is correct in that this feature is documented by perl books,
>>  but the right way to support the feature is to change /bin/sh and
>>  not the command interpreter.  The PR includes a followup reply from
>>  Ahmon Dancy <dancy_at_dancysoft.com> with some additional proof that
>>  the change to the command interpreter was the wrong way to fix this.
>>
>>  Since this perl feature is documented in many places (including the
>>  famous "Camel" book from O'Reilly), we can not just drop the support
>>  in the command interpreter.  But if we first fix /bin/sh then I
>>  believe we can drop it.
>
>    Err, your terminology is a bit off (/bin/sh is the "command
>interpreter"); what we're talking about is the behavior of the
>execve() system call in the kernel, specifically the imgact_shell
>image activation module. When the system sees that a file needs to
>be interpreted by something (e.g. sh, perl, python, or some other
>language interpreter) it parses the interpreter line specified at
>the top of the file (#!/bin/sh) and sets up to invoke that with
>the original file as the argument.
>
>    ...but I see what you're saying and I agree with the thought.
>The interpreter should decide if the # is a comment, not the kernel.

Since the above message, the execve() system call was fixed, but we
never changed the behavior of /bin/sh to match.  I recently noticed
that some of my scripts broke due to this combination, and today one
of my friends also mentioned that some of their scripts were broken
after they upgraded to the latest 5.3-stable.

I remember someone saying that they were going to fix /bin/sh, but I
don't remember who, and it looks like I didn't save that email.  So
I wrote up the following update, and hope to commit it sometime soon.
It seems to work fine, but I want to test it a bit after doing some
buildworlds on three different platforms.

Index: options.c
===================================================================
RCS file: /home/ncvs/src/bin/sh/options.c,v
retrieving revision 1.21
diff -u -r1.21 options.c
--- options.c	6 Apr 2004 20:06:51 -0000	1.21
+++ options.c	1 Feb 2005 01:53:52 -0000
_at__at_ -67,6 +67,7 _at__at_
  char *optptr;			/* used by nextopt */

  char *minusc;			/* argument to -c option */
+STATIC int found_eoo;		/* found '-' or '--' in the option list */


  STATIC void options(int);
_at__at_ -82,6 +83,7 _at__at_
  void
  procargs(int argc, char **argv)
  {
+	char *ap;
  	int i;

  	argptr = argv;
_at__at_ -91,6 +93,23 _at__at_
  		optlist[i].val = 2;
  	privileged = (getuid() != geteuid() || getgid() != getegid());
  	options(1);
+	/*
+	 * If an end-of-options marker ('-' or '--') is followed by an arg
+	 * of '#', then skip over all args after the marker.  Some scripting
+	 * languages (e.g.: perl) document that /bin/sh will implement this
+	 * behavior, and they recommend that users take advantage of it to
+	 * solve certain issues that can come up when writing a perl script.
+	 * Yes, this feature is in /bin/sh to help users write perl scripts.
+	 */
+	if (found_eoo) {
+		ap = *argptr;
+		if (ap != NULL && ap[0] == '#' && ap[1] == '\0') {
+			while (*argptr != NULL)
+				argptr++;
+			/* We need to keep the final argument */
+			argptr--;
+		}
+	}
  	if (*argptr == NULL && minusc == NULL)
  		sflag = 1;
  	if (iflag == 2 && sflag == 1 && isatty(0) && isatty(1))
_at__at_ -142,6 +161,7 _at__at_
  	int val;
  	int c;

+	found_eoo = 0;
  	if (cmdline)
  		minusc = NULL;
  	while ((p = *argptr) != NULL) {
_at__at_ -149,6 +169,7 _at__at_
  		if ((c = *p++) == '-') {
  			val = 1;
                          if (p[0] == '\0' || (p[0] == '-' && p[1] == '\0')) {
+				found_eoo = 1;
                                  if (!cmdline) {
                                          /* "-" means turn off -x and -v */
                                          if (p[0] == '\0')


-- 
Garance Alistair Drosehn            =   gad_at_gilead.netel.rpi.edu
Senior Systems Programmer           or  gad_at_freebsd.org
Rensselaer Polytechnic Institute    or  drosih_at_rpi.edu
Received on Tue Feb 01 2005 - 03:09:23 UTC

This archive was generated by hypermail 2.4.0 : Wed May 19 2021 - 11:38:27 UTC