0

I am trying to wrap a shell script so that it may be called from a Windows program inside Cygwin. Following up on a previous question, I thought it was enough to pass the arguments of the script to the wrapper as follows:

#include <stdlib.h>
#include <unistd.h>

int
main (int argc, char *argv[])
  {

     /* WARNING: Only use an absolute path to the script to execute,
      *          a malicious user might fool the binary and execute
      *          arbitary commands if not.
      * */

     system ("~/bin/script.sh \"$*\"");

     return 0;
   }

The script runs, but somehow cannot pass the arguments to the wrapper (I guess?). Coming from a DOS/Win background, this shell scripting thing is somewhat mysterious to me. What is wrong with this approach?

4
  • Are you hoping the "$*" will expand to your parameters? That doesn't work in a C program, only in shell scripts. In C you'll have to loop over the argv array that was passed to main, and add each parameter from there (separated by spaces) to the string you pass to system(). Commented Jan 31 at 0:41
  • indeed; i figured: if you pass control to the system, the shell would do the right thing... Commented Jan 31 at 0:54
  • now I see I was wrong: the system() function simply passes the argument to the OS, missing some capabilites of the shell, if any... Commented Jan 31 at 23:44
  • @Chad, you were right; if you turn your comment into an answer, with a little bit of background, I'll accept it... Commented Feb 1 at 14:44

1 Answer 1

1

Firstly, "$*" doesn't work in C programs. You'll need to iterate through argv, and append all the arguments to a string.

Secondly, "$*" isn't even that great in shell, you should usually use "$@" because it preserves arguments separation.

Thirdly, what system() does might depend what compiler and library you are using. If it's a windows compiler, I'm not sure its libraries would know how to execute either "~" tilde, or the shell script. I know you said you're using cygwin, but you didn't say if you were using the cywin compiler or a windows compiler.

Fourthly, after all, why would you want to to write a C program to wrap cygwin? I don't know what a "windows process" is... but windows can execute c:/cygwin/bin/bash script.sh arg arg arg without wrapping it. If I really needed a windowsy thing to call cygwin, I'd probably write a .bat script calling bash.

Sign up to request clarification or add additional context in comments.

15 Comments

So (3) explains it well: I was being lazy, and assumed that the compiler would do the right thing for the given platform, so Cygwin's gcc (the one I've been using) would transfer control to its "native" shell (bash, I suppose), while mingw32's would do the same and pass control to Win's cmd. That assumption was (partly) wrong: the system() function indeed sends script.sh for execution, but the script needs to be fed the command line already parsed, as the shell's functionality (wildcard expansion, for instance, but not the ~ shortcut) is partly disabled by the wrapping. correct?
@jarnowicz system() is ususally considered a bit of a lazy way to execute a program because it doesn't execute it directly, it uses a shell to execute it. So on unix it probably does /bin/sh -c "the string you passed in". On a windows compiler it probably uses cmd.com. So those would give quite different results. And you have to execute another process you don't really need... a shell. Windows compilers probably have some kind of system call like exec() or execv() or something like that, where you pass in the arguments directly and separately and avoid any shell parsing
@jarnowicz I still don't really understand why you need a "windows native" executable. Under cygwin, bash.exe is in some respects a "windows native" executable, depending how you define windows native... but it's native enough that other windows programs should be able to execute it with appropriate arguments. And native windows programs that have cause to be executing other programs should probably know how to execute .bat programs, so if for some reason you can't execute c:/cygwin/bin/bash.exe or. whatever you need to launch your haskell, you should be able to launch it via a bat script also
In the old old days of unix, any text file was assumed to be shell. Then later, someone invented #! syntax, so that if the beginning of a text file started with #!/bin/perl for example, the shell would read that, and call that text file with the appropriate perl interpreter. Later, somebody decided to put the #! behavior in the UNIX kernel itself. However, just because unix did that convenience, and windows didn't, doesn't stop you doing it. If "bar" is your haskell script, and "ghc" is your haskell interpreter, you can execute "ghc" "bar" to run your script.
If you have this problem a lot, one would want to write a program exec() function that interprets the #! .... you get that if you compile your program with cygwin for example. If you could integrate such a portable function into haskell, that would be one solution. Another possibility is that exec() functions compiled by windows compilers already know that files ending in .BAT are to be interpreted by CMD.com, in the same way a unix program might assume it is to use /bin/sh. So you could write a file BAR.BAT and have it call your program.
|

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.