jc@minya.UUCP (John Chambers) (08/26/89)
Well, here I am again, with yet another puzzle. It keeps coming to my attention that there are still Unices about that don't understand the "#!" notation. You'd think by now that everyone would realize what a Good Idea this is, and it'd have been installed everywhere. I realized how slow things can be when last week I tried some of my scripts for for first time on a brand-new, out-of-the-box Sys/V release 3.something, and to my surprise, the ones that started with lines like "#!/bin/awk" or "#!/bin/msh" (that's my menu shell) got some funny Bourne-shell diagnostics (rather than the awk or msh diagnostics that I expected ;-). Well, I decided to try to solve this problem once and for all, in the obvious way. I wrote myself a shell that I call ish (for Indirect SHell), and installed it in /bin, and also linked /bin/sh to /bin/bsh. After a bit of testing, I did rm /bin/sh ln /bin/ish /bin/sh and this should have solved the problem. What ish does, of course, is examines its command-line args, figures out what file the caller intended to exec, and opens it for reading. If it starts with "#!", ish does the obvious thing. It is, of course, quite paranoid about getting things wrong, so if it gets at all puzzled about what it should do, it just punts the job to /bin/bsh. For true binary files, of course, it never gets invoked, because the kernel knows how to handle that case. The problem is simple: when I exec a script directly, the kernel doesn't run /bin/sh, it runs /bin/bsh! I can prove this easily, since ish always writes a line to an audit trail showing when and how it was called. This code isn't conditional; there is no way that ish can work without writing to the audit trail. When I boot the machine, the audit trail shows a whole lot of entries from all the subprocesses started by /etc/*rc, and whenever anyone calls system(), the audit trail gets a new line. So basically the trick works. But there seems to be some sort of deal going between the Bourne shell and the kernel, so that when bsh starts up, it tells the kernel "Don't pay any attention to /bin/sh; I'm the real shell", and the kernel believes it. Does anyone know how this works? I'd like to see if my program can intercede and convince the kernel that it's the shell (after all, it *is* /bin/sh). I'd like an RTFM response or two. I've spent some time poring through some FMs, and so far I haven't even found any admission that the Unix kernel knows how to run scripts. The descriptions of the exec*() calls only talk about executable binary files, as does Bach's book. I've yet to see any mention of the "#!" notation in any document anywhere; I've picked it up by word-of-mouth (including a bunch of flames in several newsgroups about the idiots who don't use it correctly; such flames seems to be the best way to learn how it works. :-) Can someone explain what's going on, and why my imposter shell (hey, maybe that's what "ish" stands for |^) gets invoked correctly in every case except when a script is execed directly? I am truly bemused by this one. [A free copy of ish will be emailed (if possible;-) to the first five individuals who correctly answer the question...] -- #echo 'Opinions Copyright 1989 by John Chambers; for licensing information contact:' echo ' John Chambers <{adelie,ima,mit-eddie}!minya!{jc,root}> (617/484-6393)' echo '' saying
cpcahil@virtech.UUCP (Conor P. Cahill) (08/27/89)
In article <5@minya.UUCP>, jc@minya.UUCP (John Chambers) writes: > The problem is simple: when I exec a script directly, the kernel > doesn't run /bin/sh, it runs /bin/bsh! This is your problem. The kernel doesn't interpret your command and run the shell, the shell does. The shell realizes that you wish to execute a sub shell and just forks without having to re-exec himself. > But there seems to be some sort of deal going between the Bourne > shell and the kernel, so that when bsh starts up, it tells the > kernel "Don't pay any attention to /bin/sh; I'm the real shell", > and the kernel believes it. Does anyone know how this works? I'd > like to see if my program can intercede and convince the kernel that > it's the shell (after all, it *is* /bin/sh). Like I said, the kernel plays no part in this it is the shell itself. > Can someone explain what's going on, and why my imposter shell (hey, > maybe that's what "ish" stands for |^) gets invoked correctly in every > case except when a script is execed directly? If you want to bypass this you can change the exec to be an exec of "/bin/sh script" and you will get what you want, but not the way that you want it. -- +-----------------------------------------------------------------------+ | Conor P. Cahill uunet!virtech!cpcahil 703-430-9247 ! | Virtual Technologies Inc., P. O. Box 876, Sterling, VA 22170 | +-----------------------------------------------------------------------+
wolfgang@mgm.mit.edu (Wolfgang Rupprecht) (08/27/89)
In article <5@minya.UUCP> jc@minya.UUCP (John Chambers) writes: [ questions on replacing /bin/sh w. a dispatcher for the #!/bin/foo first line in shell scripts ] >The problem is simple: when I exec a script directly, the kernel >doesn't run /bin/sh, it runs /bin/bsh! I can prove this easily [...] Its *not* the kernel. It is /bin/sh (called /bin/bsh in your system) that is taking the short-cut. The real /bin/sh doesn't need to exec a copy of /bin/sh. It knows that it is the "True" /bin/sh and simply forks passing the command file's ascii contents to the forked copy of itself. I executing a non-builtin is done roughly like this: if (fork == 0) { execle(command_name, ...); /* what, still here? Must be a shell script, run it ourselves */ top_lev_shell_interpreter(fopen(command_name), ...); exit(...); }else wait(...); -wolfgang ---- Wolfgang Rupprecht ARPA: wolfgang@mgm.mit.edu (IP 18.82.0.114) TEL: (703) 768-2640 UUCP: mit-eddie!mgm.mit.edu!wolfgang
debra@alice.UUCP (Paul De Bra) (08/28/89)
In article <5@minya.UUCP> jc@minya.UUCP (John Chambers) writes: >... >But there seems to be some sort of deal going between the Bourne >shell and the kernel, so that when bsh starts up, it tells the >kernel "Don't pay any attention to /bin/sh; I'm the real shell", >and the kernel believes it. Does anyone know how this works? I'd >like to see if my program can intercede and convince the kernel that >it's the shell (after all, it *is* /bin/sh). >... Hmm, RTFM doesn't seem to help, and neither the Bach book indeed. A possible explanation however is that if the Bourne shell wants to execute it forks off a child which execs. If the exec fails the shell thinks the file must be a shell script so it again forks off a child which does not exec /bin/sh because it thinks it already IS /bin/sh. It just tries to run the script. So the kernel has nothing to do with it. The shell just doesn't exec "itself" because it knows it is "itself". Hope someone can confirm whether this is indeed what's happening? Paul. -- ------------------------------------------------------ |debra@research.att.com | uunet!research!debra | ------------------------------------------------------
gwyn@smoke.BRL.MIL (Doug Gwyn) (08/28/89)
In article <5@minya.UUCP> jc@minya.UUCP (John Chambers) writes: >the "#!" notation. You'd think by now that everyone would realize >what a Good Idea this is, and it'd have been installed everywhere. I think it's slated for SVR4.0. However, not everyone agrees that it's a Good Thing. It causes problems when porting scripts across systems, because the various interpreter utilities may not have identical pathnames across systems. Also, some of us have relied on System V NOT understanding the #! convention, and our scripts will break when SVR4.0 arrives. >The problem is simple: when I exec a script directly, the kernel >doesn't run /bin/sh, it runs /bin/bsh! No, it's run under whatever shell you're already running. The shell forks a subshell to handle the script, after the direct exec() system call fails. >I've yet to see any mention of the "#!" notation in any document anywhere; It's documented in the 4.3BSD PRM under EXECVE(2).
pc@cs.keele.ac.uk (Phil Cornes) (09/04/89)
From article <5@minya.UUCP>, by jc@minya.UUCP (John Chambers): > Well, here I am again, with yet another puzzle..... > > The problem is simple: when I exec a script directly, the kernel > doesn't run /bin/sh, it runs /bin/bsh..... > The exec command is actually a shell built in command so your 'ish' won't find it and will therefore execute /bin/bsh to sort it out. > > I'd like an RTFM response or two. I've spent some time poring through > some FMs, and so far I haven't even found any admission that the Unix > kernel knows how to run scripts. > The UNIX kernel *doesn't* know how to execute scripts, that is done by the C library interface to the exec*() system calls by spawning a shell to cope with the script. > > [A free copy of ish will be emailed (if possible;-) to the first five > individuals who correctly answer the question...] > Yes please.....? Phil Cornes I just called to say ..... -----------* JANET: cdtpc@uk.ac.stafpol.cr83 Phone: +44 (0)785 53511 x6058 Smail: Staffordshire Polytechnic, Computing Department Blackheath Lane, STAFFORD, ST18 0AD, ENGLAND.