llj@kps.UUCP (Leif Ljung /DP) (06/27/90)
I have a program that I want to do a general exec(2) sometimes executing a binary program, sometimes a shell-script preferably using PATH. Say I have the program `prog' - if this is a script I add the '#! /bin/sh' at the top. Can I exec(2) that? No. The only way I have been able to exec the script is by executing a one-liner containing `#! /bin/sh /path/prog. ' But this is not what I want. Not only is the first line limited in length - 32 chars according to exec(2) - it also requires a secondary file that I do not want, I just want to feed the script itself into /bin/sh using the exec(). Is there a way to do this? The system is a Pyramid running BSD4.3. Any clues? --leif --------------- Leif Ljung, Kuwait Petroleum, Stockholm, SWEDEN (llj@kps.se||uunet!mcsun!sunic!kps!llj)
cookson@helios.mitre.org (Cookson) (06/28/90)
In article <661@kps.UUCP> llj@kps.se (Leif Ljung /DP) writes: >I have a program that I want to do a general exec(2) sometimes >executing a binary program, sometimes a shell-script preferably >using PATH. >Say I have the program `prog' - if this is a script I add the >'#! /bin/sh' at the top. Can I exec(2) that? No. > >The only way I have been able to exec the script is by executing >a one-liner containing `#! /bin/sh /path/prog. ' > >But this is not what I want. Not only is the first line limited in >length - 32 chars according to exec(2) - it also requires a secondary >file that I do not want, I just want to feed the script itself into >/bin/sh using the exec(). Is there a way to do this? > Well, I'm not sure if this is what you want, but I'll give it a try. If I uderstand the question, you want a 'C' program to be able to exec. The file that it exec's can be either an executeable, or a shell script, and you want to be able to specify just the filename to be execed, and have exec look it up in the PATH environment variable. Yes?? Ok if that is the case, then just do this: execlp("file_to_be_execed", "file_to_be_execed", (a list of arguments, if any, separated by commas), (char *) 0); That should do the trick. Hope this helps, Dean % Dean Cookson $ Anyone can be taught to sculpt % % dcookson@mitre.org $ Michaelangleo would have had to % % {devax,et al..}!linus!mbunix!helios!cookson $ have been taught how not to. % % Disclaimer: My opinions are my own, and $ The same is true of great % % are of questionable sanity $ programmers %
moliver@pyrshadow (Mike Oliver) (06/28/90)
This really isn't (an answer to) a C question; followups have been redirected to comp.unix.questions. In article <661@kps.UUCP> llj@kps.se (Leif Ljung /DP) writes: >I have a program that I want to do a general exec(2) sometimes >executing a binary program, sometimes a shell-script preferably >using PATH. >Say I have the program `prog' - if this is a script I add the >'#! /bin/sh' at the top. Can I exec(2) that? No. I don't have a problem doing this. I don't know how you're managing the PATH variable, but if you provide the coorect relative path of the target file you can exec() it regardless of whether it's a program or an interpreter script. There's a tiny demo program on the end of this post - you might want to compare it against your code. My favourite way to get this wrong is to forget that *argv[0] in the exec() call should be the name of the executable, usually the same as the path that you supply as the first parameter to exec(). If you're still stuck after that, mail me your code and I'll see if I can find what might be causing the problem. >The system is a Pyramid running BSD4.3. Meaning that it's running OSx and you're working in the ucb universe ? If you're building in the att universe you should be aware that the ability to exec() a script is configurable, and it defaults to being disabled. Don't ask me why, I don't know. This hinges on the universe that your program was built under, not on the universe in which it runs. Check your makefile to make sure the build isn't running under att. If that's the case you'll get an "Exec format error" when you try to exec a script. Demo program and sample script are below, hit "n" if you've had enough already. --- 8< ------ 8< ------ 8< ------ 8< ------ 8< ------ 8< ------ 8< --- /* This program will exec() its first argument, passing any * additional arguments to the exec()'d program. * * Try "a.out /bin/ls -l" for starters. Then try the script * below, which will print "hello world" and then print its * arguments. */ #include <stdio.h> #include <sys/wait.h> main( argc, argv ) int argc; char **argv; { extern char **environ; union wait waitstatus; char *cmdpath; if ( argc < 2 ) { /* Not enough info on the command line. */ fprintf( stderr, "%s: %s <command> [args ...]\n", argv[0], argv[0] ); exit( -1 ); } switch ( fork() ) { case 0: /* This is the child */ cmdpath = *(++argv); (void) execve( cmdpath, argv, environ ); perror( "child ... execve() failed" ); break; case -1: /* This is the parent, and the fork failed */ perror( argv[0] ); break; default: /* This is the parent, the fork() worked */ fprintf( stdout, "parent ... deceased PID is %d\n", wait( &waitstatus ) ); fprintf( stdout, " ... status is %d\n", waitstatus.w_status ); break; } } --- 8< ------ 8< ------ 8< ------ 8< ------ 8< ------ 8< ------ 8< --- #! /bin/sh # Simple script, just says "hello world" and then prints its arguments. echo "hello world" echo $* --- 8< ------ 8< ------ 8< ------ 8< ------ 8< ------ 8< ------ 8< --- Cheers, Mike. moliver@pyramid.com {allegra,decwrl,hplabs,munnari,sun,utai,uunet}!pyramid!moliver
cpcahil@virtech.uucp (Conor P. Cahill) (06/28/90)
In article <661@kps.UUCP> llj@kps.se (Leif Ljung /DP) writes: >I have a program that I want to do a general exec(2) sometimes >executing a binary program, sometimes a shell-script preferably >using PATH. >Say I have the program `prog' - if this is a script I add the >'#! /bin/sh' at the top. Can I exec(2) that? No. The correct way to do this (one that will work on systems that understand the "#!" and those that don't) is as follows: place "#!/bin/sh" as the first line for the program. in the code that you wish to exec the program do the following: execvp("prog",argv); /* argv is setup accordingly */ /* * if we get here, prog was not executed by the kernel, * so this system doesn't understand "#!" and we must call * the shell ourselves */ arg_str[0] = '\0'; for(i=0; argv[i] != NULL; i++) strcat(arg_str,argv[i]); sh_argv[0] = "sh"; sh_argv[1] = "-c"; sh_argv[2] = arg_str; sh_argv[3] = (char *)0; execvp("sh",sh_argv); -c is used so sh will use PATH to find the program. NOTE: I did not compile or test the above code, your milage may vary. -- Conor P. Cahill (703)430-9247 Virtual Technologies, Inc., uunet!virtech!cpcahil 46030 Manekin Plaza, Suite 160 Sterling, VA 22170
leo@ehviea.ine.philips.nl (Leo de Wit) (06/28/90)
In article <661@kps.UUCP> llj@kps.se (Leif Ljung /DP) writes: |I have a program that I want to do a general exec(2) sometimes |executing a binary program, sometimes a shell-script preferably |using PATH. |Say I have the program `prog' - if this is a script I add the |'#! /bin/sh' at the top. Can I exec(2) that? No. Yes you can. | |The only way I have been able to exec the script is by executing |a one-liner containing `#! /bin/sh /path/prog. ' | |But this is not what I want. Not only is the first line limited in |length - 32 chars according to exec(2) - it also requires a secondary |file that I do not want, I just want to feed the script itself into |/bin/sh using the exec(). Is there a way to do this? | |The system is a Pyramid running BSD4.3. |Any clues? Yes, assuming you got the semantics of the exec(2) functions/syscalls correct, you probably forgot to make the script executable. If not, show us what your exec() call looks like. Another hint: put a perror("This is what went wrong"); after the exec() call. 9 out of 10 times you will see the problem immediately. Leo.
caxwgk@pkinbg.UUCP (Wolfgang G. Kuehnel) (06/28/90)
From article <661@kps.UUCP>, by llj@kps.UUCP (Leif Ljung /DP): > I have a program that I want to do a general exec(2) sometimes > executing a binary program, sometimes a shell-script preferably > using PATH. > Say I have the program `prog' - if this is a script I add the > '#! /bin/sh' at the top. Can I exec(2) that? No. > The system is a Pyramid running BSD4.3. > Any clues? I remember that we've done this using execve() after forking a program. The program fork()ed and the child process execve()ed a /bin/sh-script. We put '#! /bin/sh' at the top line and that worked. We had to make sure that the arguments to execve() were correct: *path had to be a full path *containing the file name at the end* **argv[0] had to be the filename (again) **envp could be point to NULL The script had to be executeable for the effective uid of the forked child process. We were working under SunOs 4.0.3, which should make no difference to BSD4.3 in this respect. Greetings Wolfgang Kuehnel Philips Kommunikations Industrie AG Nuernberg / West Germany
martin@mwtech.UUCP (Martin Weitzel) (06/29/90)
In article <1990Jun27.225015.1956@virtech.uucp> cpcahil@virtech.UUCP (Conor P. Cahill) writes: >In article <661@kps.UUCP> llj@kps.se (Leif Ljung /DP) writes: >>I have a program that I want to do a general exec(2) sometimes >>executing a binary program, sometimes a shell-script preferably >>using PATH. >>Say I have the program `prog' - if this is a script I add the >>'#! /bin/sh' at the top. Can I exec(2) that? No. > >The correct way to do this (one that will work on systems that understand >the "#!" and those that don't) is as follows: Though I usually appreciate Conors experience and good advice, I must object this time: > place "#!/bin/sh" as the first line for the program. Well, there are some good arguments in favor for a first line that starts with a colon (:) in shell scripts. At least this helps in some (IMHO brain damaged) C shells that consider every text file which starts with a hash (#) to be a C-shell script. (I've had some discussions in the past, if it was "legal" for the bourne shell to add #-comments, after the C-shell "invented" them and obviously claimed exclusive rights to use them ...) > in the code that you wish to exec the program do the following: > > execvp("prog",argv); /* argv is setup accordingly */ > > /* > * if we get here, prog was not executed by the kernel, > * so this system doesn't understand "#!" and we must call > * the shell ourselves > */ Wrong: At least in SysV(%) for which I can check this out right now, the facts are that execvp() executes a shell if the given file name turns out to be a text file with appropriate x-bits set. THIS DOESN'T DEPEND ON THE FIRST LINE OF THE TEXT-FILE! Behavior differs with "execv()", which will not only do *no* path search, but also never execute a text file, regardless of what the first line contains (I'm aware the latter was not what Conor claimed). %: If memory serves, behaviour was the same in SysIII-derived XENIX. > arg_str[0] = '\0'; > for(i=0; argv[i] != NULL; i++) > strcat(arg_str,argv[i]); WRONG (forgets to embed blanks or some other IFS-seperator) and DANGEROUS - at least you should count the length of your arguments and allocate space for arg_str dynamically. (I hope that it was not meant this way: As I exec anyway, I may leave total desaster behind me :-).) > > sh_argv[0] = "sh"; > sh_argv[1] = "-c"; > sh_argv[2] = arg_str; > sh_argv[3] = (char *)0; > execvp("sh",sh_argv); > >-c is used so sh will use PATH to find the program. Yes, but this is only *one* of the effects of "-c". Anotherone is that the shell fully re-interprets the arguments. If this is desirable or not will generally depend on the problem, but as the method here was used as substitute for exec-ing a script from the kernel, the behaviour will differ (Again IMHO; I have no such kernel here to check this, but I would be surprised if the kernel had not only mechanisms to exec the program given in the first line, but also to interpret args.) >NOTE: I did not compile or test the above code, your milage may vary. *If* we do so many things manually here, why not open the file, read the first line and exec a given program in case of #!prog in the way UCB-derivates do it in the kernel? Any volunteers to write (and compile and test!!) such code? You should call it something like "ucb_exec" and make the same functions available that are normaly provided by exec. This should not be more than one day work for any halfway experienced C-programmer. -- Martin Weitzel, email: martin@mwtech.UUCP, voice: 49-(0)6151-6 56 83