NetBSD-Bugs archive

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index][Old Index]

Re: bin/45430: ash uses argv[0] as $0 for scripts without #!

Thanks for answers and suggestions, David!
Please see my replies below.

On 11/06/2011 02:30 AM, David Holland wrote:

  Well... I also see this:

  valkyrie% pwd
  valkyrie% cat thingy
  echo "$0"
  valkyrie% sh -c 'env PATH=/tmp/testdir thingy'
  valkyrie% csh -c 'env PATH=/tmp/testdir thingy'
  valkyrie% ksh -c 'env PATH=/tmp/testdir thingy'
  valkyrie% bash -c 'env PATH=/tmp/testdir thingy'
  valkyrie% tcsh -c 'env PATH=/tmp/testdir thingy'
  valkyrie% zsh -c 'env PATH=/tmp/testdir thingy'

  which is what you want, right?

Yes, but this is done by "env", which probably calls execvp. BTW, stock
Android doesn't have it.

  I'm not convinced that you're actually using our shell... especially
  since you're referring to it as ash, which was a Linuxish branch that
  diverged a long time ago.

Well, I'm not really sure myself, but it looks pretty close. You could take
a look yourself. The latest available source for Gingerbread is at
under "sh". We're using the unreleased Honeycomb version, though.

This is what happens on my Galaxy S II (it is only possible to execute using

$ strings /system/bin/sh | grep NetBSD
$NetBSD: alias.c,v 1.12 2003/08/07 09:05:29 agc Exp $
$NetBSD: arith.y,v 1.17 2003/09/17 17:33:36 jmmv Exp $
$NetBSD: arith_lex.l,v 2005/04/07 11:38:58 tron Exp $
$NetBSD: cd.c,v 1.34 2003/11/14 20:00:28 dsl Exp $
$NetBSD: error.c,v 1.31 2003/08/07 09:05:30 agc Exp $
$NetBSD: eval.c,v 2005/06/13 22:03:51 tron Exp $
$NetBSD: exec.c,v 1.37 2003/08/07 09:05:31 agc Exp $
$NetBSD: expand.c,v 2005/04/07 11:37:39 tron Exp $
$NetBSD: input.c,v 1.39 2003/08/07 09:05:32 agc Exp $
$NetBSD: jobs.c,v 1.62 2003/12/18 00:56:05 christos Exp $
$NetBSD: main.c,v 1.48 2003/09/14 12:09:29 jmmv Exp $
$NetBSD: memalloc.c,v 1.28 2003/08/07 09:05:34 agc Exp $
$NetBSD: miscbltin.c,v 2005/04/07 11:34:20 tron Exp $
$NetBSD: mystring.c,v 1.16 2003/08/07 09:05:35 agc Exp $
$NetBSD: options.c,v 1.37 2004/10/30 19:29:27 christos Exp $
$NetBSD: parser.c,v 1.57 2004/06/27 10:27:57 dsl Exp $
$NetBSD: redir.c,v 1.29 2004/07/08 03:57:33 christos Exp $
$NetBSD: show.c,v 1.26 2003/11/14 10:46:13 dsl Exp $
$NetBSD: trap.c,v 1.31 2005/01/11 19:38:57 christos Exp $
$NetBSD: output.c,v 1.28 2003/08/07 09:05:36 agc Exp $
$NetBSD: var.c,v 1.36 2004/10/06 10:23:43 enami Exp $

  Try this:

  -- ; exec lua $(type "$0" | cut -d' ' -f3) "$@"

Well, since the stock Android doesn't have "cut", the above won't work as
is, but something like this will:

--; exec lua "`type \"\$0\" | (read script is a tracked alias for path; echo 
\"\$path\")`" "$@"

Yet, this is far from pretty.

  While "type" doesn't work in csh/tcsh, at least here both those shells
  run unidentified scripts with /bin/sh. It looks like they do for you
  too, as 2>  isn't csh-friendly. However, if it becomes necessary you
  can probably do something like type "$0" || which "$0".

Thanks! Indeed csh/tcsh use /bin/sh in this case. I didn't notice that,
although I should have expected this. This actually solves the problem,
because using "command -v" will work. Like this:

--; exec lua "`command -v \"\$0\"`" "$@"

This would cover all the shells nicely without a need to change sh.

  Note that "-- 2>/dev/null" still generates a "--: Not found" message
  with sh and other shells. To get rid of it, create an executable file
  on the path called "--" that does nothing. :-)  (Whether that's viable
  or not depends on the environment you're assuming, I guess.)

Yes, that's precisely what we're doing currently :)

  However, a better approach entirely seems to me to run your tests as
  "test foo" and "test bar" and so on rather than "foo" and "bar". (If
  your tests are run manually this is only a minor hassle, and perhaps a
  negative hassle if you support something like "test \?". If your tests
  are run from scripts or makefiles or whatnot it doesn't matter at
  all.) Then you can have the program "test" figure out what environment
  it's in and run the test scripts from the proper known location in
  either case.

  Something like

     case "$PATH" in
        /system*|*:/system/*) DIR=/system/whatnot/libexec/tests;;
        *) DIR=/usr/local/libexec/tests;;
     exec lua "$DIR"/"$TEST" "$@"

  would do the trick. Since all that's shell builtins it shouldn't even
  be particularly slow. If you really need to worry about it being run
  as csh script text by csh there's a standard trick for detecting that
  and execing sh, which I forget but should be easily findable with

  You can probably also combine that trick with the type/which line

Thanks for this detailed suggestion, but this is too involved and opaque.
I wanted these scripts to be as natural to use and integrate as possible.
Such big companies as mine have a lot of their own special ways to do simple
and common things as it is and I don't want to add to that pile.

   >  >   By convention the value of argv[0] is whatever the invoker supplies, 
   >  >   with most shells by (mostly tacit) convention that is the path used to
   >  >   invoke the program if a path was given (with at least one slash)
   >  This is perfectly suitable.
   >  >   and just the name if the program was found somewhere on $PATH.  In 
   >  >   cases the full path will get substituted; and, as David Laight hinted
   >  >   at, for
   >  This isn't true. At least on Linux.

  Yes it is, but I didn't mean for scripts:

  valkyrie% cat compiled.c
  int main(int argc, char *argv[]) {
     printf("%s\n", argv[0]);
     return 0;
  valkyrie% gcc compiled.c -o compiled
  valkyrie% sh -c 'env PATH=/tmp/testdir:/usr/bin:/usr/pkg/bin:/bin compiled'
  valkyrie% csh -c 'env PATH=/tmp/testdir:/usr/bin:/usr/pkg/bin:/bin compiled'
  valkyrie% ksh -c 'env PATH=/tmp/testdir:/usr/bin:/usr/pkg/bin:/bin compiled'
  valkyrie% bash -c 'env PATH=/tmp/testdir:/usr/bin:/usr/pkg/bin:/bin compiled'
  valkyrie% tcsh -c 'env PATH=/tmp/testdir:/usr/bin:/usr/pkg/bin:/bin compiled'
  valkyrie% zsh -c 'env PATH=/tmp/testdir:/usr/bin:/usr/pkg/bin:/bin compiled'

  So relying on the path being there is in general unwise.

As you know the shebang script execution is initiated by the kernel.
Kernel has to always supply reachable script path to the shell. Otherwise
the shell wouldn't be able to load it. Thus the executing shell can't
possibly supply an unreachable filename in this case, because it can't guess
what the user entered in the parent process.

In case of shebang-less scripts shells are in a privileged position, because
they can choose to keep the same process, having the information on whatever
the user entered. Thus they could try to imitate the execution of a binary
program. Only in this case. And I can't see any practical reason in this.

The shebang-less scripts are a corner case and it stands to reason, then, to
do what the dominant case does. Especially since this would be more

   >  I'm sorry. Yet, this is quite unexpected. I've tested it again now and it
   >  works for me even in Lynx.

  It's just Google Plus sucking, not your fault.

Well, it's probably my fault for choosing it. Yet, it is still better than
Facebook in this regard :)

  I think the summary of this mail is:

  1. I can't reproduce the behavior you're seeing, so as far as I can
  tell what you want is in place (even in ksh);

Well, maybe it is my fault for not explaining it clearly enough.

  2. you can have the shell search the path for you explicitly;

Yes, it seems so.

  3. or you could do the whole thing a different way entirely.

Yes I could, but I like this way better :)

Thanks once again :)


Home | Main Index | Thread Index | Old Index