can't execute bash command via c standard system function - c

the code snippet I wrote is like this:
#include <stdlib.h>
int main()
{
system("/bin/bash ls");
}
when I compile and execute the binary, I got the result:
/bin/ls: /bin/ls: cannot execute binary file
so what's the thing missing here?

ls is an actual system binary. it's not a built-in shell command. All you need is system("ls"). Right now you're trying to pass the contents of the ls binary file into bash as a script.

Do not use system() from a program , because strange values for some environment variables might be used to subvert system integrity. Use the exec(3) family of functions instead, but not execlp(3) or execvp(3). system() will not, in fact, work properly from programs with set-user-ID or set-group-ID privileges on systems on which /bin/sh is bash version 2, since bash 2 drops privileges on startup. (Debian uses a modified bash which does not do this when invoked as sh.)
In your case , ls is not built in command in shell so system() is not working.
You can check using type <cmd_name> command to know that cmd_name is built-in or not.
For more man system()

If no options are specified, the argument to /bin/bash is the name of a file containing shell commands to execute.
To execute commands specified on the command line, use the -c option: /bin/bash -c ls.
As others have noted, there are security considerations when doing this, so you should seek alternatives.

Related

Is is possible to implement internal shell command (shell builtin) by only using the exec() functions?

I want to implement some Linux commands by only using the exec() family of functions. When I use external commands such as "ls", "whoami", it runs well. However, I can't run internal commands (shell builtins) such as "export". Is there any other way to run those commands? And also, why can system() implement those internal commands even though it uses execl() function?
The Linux implementation of system does indeed use execl, but it uses it to run a shell, not to directly invoke the utility. man system is quite explicit:
The system() library function uses fork(2) to create a child process that executes the shell command specified in command using execl(3) as follows:
execl("/bin/sh", "sh", "-c", command, (char *) 0);
So system runs an instance of the standard shell (/bin/sh), passing it two command-line parameters: -c and the argument to system. Shells are expected to interpret the command-line flag -c as requesting the the shell execute the following argument as a shell command. The shell will certainly be able to execute its own builtins from a -c argument in the same way that it executes them if you type them interactively.
However, although you can execute a cd or export command with system, you will find that it is utterly pointless because it works on the execution environment of the shell invoked by system. That shell will terminate as soon as it finishes executing the command it has been asked to execute, so any changes to its execution environment will immediately vanish.
So that's not very useful if you are trying to write a shell. You will want cd to actually change working directories and export to modify your shell's environment variables. So, just like the system shell, you'll have to implement your own builtins. As the word "builtin" implies, these commands are interpreted directly by the shell itself, rather than being passed to some external utility to implement.
For these particular commands, you'll probably want to investigate the standard library functions setenv(3) (to modify environment variables) and chdir(2) (to change the current working directory).

How can I call a C program from a shell script? [duplicate]

I have a simple question. I want to execute a C program in a shell script. How do I do that? Thanks for your help in advance.
Assuming this is linux/unix we're talking about:
#!/bin/sh
/path/to/executable arg1 arg2
cc hello_world.c #produces a.out
./a.out #run your program
IMHO, your problem is the $PATH. Your current directory is not in PATH, so when you enter
a.out
your shell respond:
-bash: a.out: command not found
you should execute it as
./a.out
(or add "." to your PATH, but this is not recommended.)
Almost every program that you execute in a shell script is a C program (but some, often many, of the commands you execute may be built into the shell). You execute a C program in the same way as any other program:
By basename: command [arg1 ...]
The command must be in a directory searched by the shell - on your PATH, in other words.
By relative name: ./command [arg1 ...] or ../../bin/command [arg1 ...]
The program must exist and be executable (by you)
By absolute name: /some/directory/bin/command [arg1 ...]
The program must exist and be executable (by you)
One of the beauties of Unix is that programs you create, whether in C or any other language, attain the same status as the system-provided commands. The only difference is that the system-provided commands are in a different place (such as /bin or /usr/bin) from commands you create (such as usr/local/bin or $HOME/bin).

How to tell if a shell command is written in Bash or C?

I'm using macOS and I noticed (via a separate article) that the cat command is written in C. But I'm sure I've read elsewhere that some shell commands (builtins?) are written in Bash.
How can you tell the difference?
UPDATE: seems I was misinformed and that no builtin commands are written in bash. What I must have read was something related to an external executable.
Use the 'file' command to determine the type of file.
Built-ins are not written in bash. The are intrinsically part of the command interpreter (which is often bash). Example: 'cd'. The 'file' command will not be able to find a built-in and will give an error.
the difference between a bash builtin and an executable is that when calling from a bash process a builtin is a function call whereas an external command forks a new process (if not in background waits for termination).
note the overhead of calling a new process
for((i=0;i<1000;i++)); do /bin/echo -n ; done
to know if a command is a builtin or an executable you can use type
type cat
type -a echo
to explicitly call echo builtin
builtin echo
to explicitly call echo command
command echo
note commands that changes process environment like cd can't be an executable because calling a sub process can't change caller's environment.

Command not found when using popen

I'm working in C and I have a problem when calling popen with the following arguments:
void exampleFunction(void)
{
.
.
.
FILE* in = popen("alias -p", "r");
.
.
.
}
When I call popen this way I get the following message:
alias: -p not found
I don't know what is actually wrong because when I call popen with the following arguments:
FILE* in = popen("ls -i", "r");
There is no problem and I'm using the same syntax.
Maybe someone realizes what's actually wrong.
The alias command is built into the shell.
popen, like system(), invokes /bin/sh to execute the specified command. Your interactive shell is probably bash, which supports a -p option to alias. /bin/sh, depending on your system configuration, probably does not.
In any case, even if this worked it wouldn't give you any useful information. The popen() call would invoke a new shell, and (again, depending on your configuration), it likely wouldn't have your aliases set up, since it's not an interactive shell.
The ls -i command works because ls is an external command, so it works the same way regardless of whether it's invoked from bash or /bin/sh, or from an interactive or non-interactive shell. (Sometimes ls can be defined as an alias or shell function, but such definitions typically don't interfere with the use of the -i option.)
alias is no executable program but a shell built-in (think of it as a "function in bash scripting language") so you can't open a process by this name. You could try to fool bash and pipe it in. Something like this untested snippet:
FILE* p = popen("/bin/bash", "r"); // Note: on non-Linux-systems you might need another path or rely on $PATH
fprintf(p, "alias -p\n");
Mind that you can't call aliases directly either.
The difference to ls is that ls exists both, as built-in an as program.

Bad Substitution Error with System command in C

I have written a C program with some system command in it. I use a software called Gromacs. Here is the snippet of C code :-
#include<stdio.h>
#include <stdlib.h>
/*I have removed unnecessary code, which works fine for me. */
int main() {
float LAMBDA=0.37;
for(LAMBDA=0.37 ; LAMBDA <0.55; LAMBDA +=0.02 ) {
system("g_bar -f md*.xvg -o -oi -oh");
system("mapfile -t a < <(g_bar -f md*.xvg -o -oi -oh | sed '/lambda/s/.*DG *//')");
printf("Free Energy:\t ");
system("echo ${a[120]}");
return 0;
}
I receive an error
sh: 1: Bad substitution
I have checked previous answers on Bad substitution. It seems dash doesn't work with arrays then how can I enable Bash for system commands ? If somebody can troubleshoot me I will be grateful.
The sh vs dash vs bash is not the root problem here.
You create a 'a' (whatever that is) in your second call to system().
Then you try to use this 'a' in the forth system() call.
But this is another shell, and 'a' does not exist here.
Each time you call system(), a new shell environment is created, and disappear at return.
What you need to do is somehow save your 'a' to some file that a subsequent call may work on.
In other words, each call to system() act as if you opened a new terminal, do your stuff and then closed it. The variables created in one terminal (shell session) do not exist in the following one.
EDIT:
And to convince you that the sh/dash/bash is not your root problem here, once you've check your commands run OK when typed in the same shell session (terminal), you can always explicitly use bash in your system() calls by;
system("bash -c do_my_stuff from_this and_that etc");
First, mapfile is a bash 4 builtin command. system runs sh, not bash.
Second, and the cause of the error message, you are using process substitution here:
<(g_bar -f md*.xvg -o -oi -oh | sed '/lambda/s/.*DG *//')
sh does not support process substitution. system runs sh, not bash.
You have several calls to system. Your last call (as shown) looks at a variable a that was created in a previous shell process, it won't exist anymore!
I suggest you write a bash script, complete with #!/bin/bash, and call that from C. You could always write out the script from C, using fopen and fprintf.
If that isn't practical, the use bash -c as suggested by #jbm. But you can't expect any persistence across calls to system except via the C program.

Resources