Is this possible?
Here is an example:
#include <stdio.h>
#include <stdlib.h>
char testString[]="blunt"
#define shellscript1 "\
#/bin/bash \n\
printf \"\nHi! The passed value is: $1\n\" \n\
"
int main(){
system(shellscript1);
return 0;
}
Now I would like to pass a value from testString to shellscript1 without having to reserve to making a temporary external script.
I've been bashing my head, and I couldn't figure out how to do it. Does anyone have any ideas?
Using the environment is possibly the simplest way to achieve it.
#include <stdio.h>
#include <stdlib.h>
char testString[]="blunt";
#define shellscript1 "bash -c 'printf \"\nHi! The passed value is: $testString\n\"'"
int main()
{
if(0>setenv("testString",testString,1)) return EXIT_FAILURE;
if(0!=system(shellscript1)) return EXIT_FAILURE;
return 0;
}
There are other ways, like generating the system argument in a buffer (e.g., with sprintf) or not using system.
system treats its argument like a a string to come after "/bin/sh", "-c". In my answer to using system() with command line arguments in C I coded up a simple my_system alternative that takes the arguments as a string array.
With it, you can do:
#define shellscript1 "printf \"\nHi! The passed value is: $1\n\" \n"
char testString[]="blunt";
int main()
{
if(0!=my_system("bash", (char*[]){"bash", "-c", shellscript1, "--", testString,0})) return EXIT_FAILURE;
return 0;
}
Related
I'm attempting to learn the remove() function in C, and I want to make a program with first gets the environmental variable with getenv() function, then uses it inside the code.
However, I get the error
"too many arguments to function remove()".
#include <stdio.h>
#include <stdlib.h>
int main()
{
char* a = getenv("USERPROFILE");
remove("%s/Desktop/remove.txt", a);
return 0;
}
If you are simply trying to combine them this should work.
I commented out some lines and put a printf so you can run it to see the result.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define MAXPATH 256
int main()
{
//char* a = getenv("USERPROFILE");
char* a = "userprofile";
char path[MAXPATH];
strcpy(path,a);
strcat(path,"/Desktop/remove.txt");
//remove(path);
printf("PATH: %s",path);
return 0;
}
_execl() is returning -1 and error message as "No such file or directory" even though the given file is there. When I run gzip command directly on command prompt it works. I am not able to understand what is it that I am missing here.
#include <stdio.h>
#include <process.h>
#include <errno.h>
void main(){
int ret = _execl("cmd.exe", "gzip.exe", "C:\\Users\\user_name\\work\\Db618\\test.txt");
printf("ret: %d \t strerror: %s\n", ret, strerror(errno));
}
Can someone give an example of how to use this function, I found one more API system() while looking for a solution, but before using that I wanted to know what is the difference in both of these on Windows platform?
According to the _execl:Your first parameter does not need to be cmd.exe, but should be the first command of the command line, like gzip.exe.
You can refer to the MSDN sample.
Finally, your program only needs to delete the initial "cmd.exe", but it should be noted that the last parameter must be NULL to indicate termination.
Here is the code:
#include <stdio.h>
#include <process.h>
#include <errno.h>
#include <cstring>
int main(int argc, const char* argv[])
{
int ret = _execl("D:\\gzip-1.3.12-1-bin\\bin\\gzip.exe" ,"-f","D:\\gzip-1.3.12-1-bin\\bin\\test.txt" ,NULL);
printf("ret: %d \t strerror: %s\n", ret, strerror(errno));
return 0;
}
If you want to use system, you can pass the command as a parameter to the system function just like using CMD to achieve the same effect.
You can use it like:
system("gzip.exe test.txt");
I have read a little and learned a little about syestem function in c.
So, assuming I have a bash file ./some.sh that takes three arguments how should I make this code work? It will not compile with an error about the buffer.
#include <stdio.h>
#include <stdlib.h>
int main(void)
{
snprintf(buffer, sizeof(buffer), "/bin/bash ./some.sh %s %s %s", target1, target2, target3);
system(buffer)
}
Slightly more complicated, but safer, would be to avoid system and explicitly call fork and some version of exec (below, I use execl). (Error handling omitted for simplicity.) This avoids the need to ensure that each argument is correctly quoted for creating a shell command line.
int main(void) {
// ...
if (fork() == 0) {
execl("/bin/bash", "./some.sh", target1, target2, target3, (char *)0);
}
}
(Note: the approach is sound; my actual C implementation may leave something to be desired.)
You've used the buffer variable without actually declaring it. This works in Bash, but not in C. If you wanted buffer to be an array of characters, say, 1024 characters long, you could write:
#include <stdio.h>
#include <stdlib.h>
int main(void)
{
char buffer[1024];
snprintf(buffer, sizeof(buffer), "/bin/bash ./some.sh %s %s %s", target1, target2, target3);
system(buffer)
}
(Of course, target1, target2 and target3 have to exist as well, but I assume those are placeholder names.)
I'm trying to run BASH commands via a C program, but i'm struggling with the function execv. I don't really know how to write the first parameter of that function. I tried with the strcat function to append the string "/bin/" with the 1st element of the argv tab, which is the command i write when I run my program, but it just doesn't work. I get a "Segmentation fault". Instead of using the strcat function I tried with strdup, but I don't know how to use it right.
Any help would be appreciated. My program is below.
#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <unistd.h>
#include <string.h>
int main(int argc, char *argv[], char *envp[]){
char *tab[] = {argv[1],NULL};
if(execve(strcat("/bin/",argv[1]), tab, envp)==-1)
{
perror("execve");
return EXIT_FAILURE;
}
return EXIT_SUCCESS;
}
regarding:
if(execve(strcat("/bin/",argv[1]), tab, envp)==-1)
This will not work ,
the literal "/bin/" is in read only memory, so cannot be changed (need a char buffer large enough to hold the full string, similar to `char string[100] = "/bin/";
Suggest:
#include <stdio.h> // perror()
#include <stdlib.h> // exit(), EXIT_FAILURE
#include <sys/types.h>
#include <sys/wait.h> // waitpid()
#include <unistd.h> // fork(), execvp()
#include <string.h> // strlen(), strcpy(), strcat()
int main( int argc, char *argv[], char *env[] )
{
(void)argc;
char *tab[] = { argv[1], NULL };
char string[strlen(argv[1]) + strlen( "/bin/" ) +1 ];
strcpy( string, "/bin/" );
strcat( string, argv[1] );
int status;
pid_t pid = fork();
switch( pid )
{
case -1: // fork failed
perror( "fork failed" );
exit( EXIT_FAILURE );
break;
case 0: // child process
execve( string, tab, env ); // does not return unless an error
perror("execve failed");
exit( EXIT_FAILURE );
break;
default:
waitpid( pid, &status, 0 );
break;
}
}
Caveat: the proposed code just hides the parameter: argc rather than properly checking it to assure the command line does contain a parameter.
Caveat: the parameter to main: env[] is not portable and should not be used. Suggest using :
extern char *environ[];
To run a shell command from a C program, you should use system(3).
If you want to get its stdout (or give its stdin, but not both) use popen(3) (don't forget to pclose such a stream).
The shell used (by system and popen) is not exactly bash but the standard POSIX /bin/sh (quite similar to bash with some restrictions).
To build that shell command (but beware of code injections in it) you can use common string functions such as snprintf and asprintf.
Notice that execve(2) does not return when it is successful, and it does not run a command thru a shell, but directly an executable program. Actually Unix shells (such as bash or /bin/sh) are using fork(2), execve(2), waitpid(2) very often and are implementing globbing. BTW system & popen are also using fork and execve on /bin/sh -c.
strcat("/bin/",argv[1])
is horribly wrong, the first argument to strcat is the overwritten destination buffer (so cannot be a string literal), and you don't check against buffer overflow.
You might want to code:
char progbuf[80];
int ln = snprintf(progbuf, sizeof(progbuf), "/bin/%s", argv[1]);
and you should check later that ln<(int)sizeof(progbuf)
BTW, your program, when you'll improve it, is not using Bash; it is directly executing some command.
I tried with strdup, but I don't know how to use it right.
Before using any function, you need to carefully read its documentation, for example strdup(3) (or type man strdup in a terminal).
Melpomene is right- you can't use strcat like that. In C, you can't return strings. What you do is pass a memory address (pointer) as the first argument in strcat, and then strcat modifies the memory pointed to by it so that it also contains the second argument of strcat. This is a process you will repeat over and over again in C, so you should understand it. Also, that strcat doesn't look safe, I bet there is a strcatn function or something like that.
I finally got to find a way to do what I wanted at the first place. Thanks to all of you guys for your help & advices ! Here's the solution !
#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <unistd.h>
#include <string.h>
int main(int argc, char *argv[], char *envp[]){
char *tab[] = {argv[1],argv[2],NULL};
char test[20] = "/bin/";
if(execve(strcat(test,argv[1]), tab, envp)==-1)
{
perror("execve");
return EXIT_FAILURE;
}
return EXIT_SUCCESS;
}
I know it might sound strange but I'm trying to find when to get this type of error when passing a wrong argument to a main program.
Let's say I have a program that accepts 1 or 2 arguments. If it's 2 arguments it can only be:
argv[0] =./programName
and
argv[1] = "-A".
Any other argv[1] other than "-A" needs to printf a "2 No such file or directory" message.
As far as I know, this is a system message, so printing it will not work for me.
DO I need to save all possible main arguments in a file and then compare the typed arguments with the ones in the file?
Right now the way I have it is:
#include <unistd.h>
#include <stdio.h>
#include <string.h>
#include <fcntl.h>
#include <stdlib.h>
#include <time.h>
#include <errno.h>
#include <sys/stat.h>
#include <sys/times.h>
#include <sys/wait.h>
int main (int argc, char *argv[]){
.....
...
if (argc == 2 && strcmp(argv[1], ARGV_2)!=0){
return(EXIT_FAILURE);
}
...
.....
}
I think ls does this with the error() function:
GNU Error_messages
Function: void error (int status, int errnum, const char *format, …)
Preliminary: | MT-Safe locale | AS-Unsafe corrupt heap i18n | AC-Safe
| See POSIX Safety Concepts.
The error function can be used to report general problems during
program execution. The format argument is a format string just like
those given to the printf family of functions. The arguments required
for the format can follow the format parameter. Just like perror,
error also can report an error code in textual form. But unlike perror
the error value is explicitly passed to the function in the errnum
parameter. This eliminates the problem mentioned above that the error
reporting function must be called immediately after the function
causing the error since otherwise errno might have a different value.
error prints first the program name. If the application defined a
global variable error_print_progname and points it to a function this
function will be called to print the program name. Otherwise the
string from the global variable program_name is used. The program name
is followed by a colon and a space which in turn is followed by the
output produced by the format string. If the errnum parameter is
non-zero the format string output is followed by a colon and a space,
followed by the error message for the error code errnum. In any case
is the output terminated with a newline.
The output is directed to the stderr stream. If the stderr wasn’t
oriented before the call it will be narrow-oriented afterwards.
The function will return unless the status parameter has a non-zero
value. In this case the function will call exit with the status value
for its parameter and therefore never return. If error returns, the
global variable error_message_count is incremented by one to keep
track of the number of errors reported.
So maybe something like this would achieve OP's goal as well as the other answers suggested before:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>
#include <error.h>
int main(int argc, char* argv[])
{
if (argc == 2 && strcmp(argv[1], "-A") != 0) {
error(ENOENT, ENOENT, "cannot access %s", argv[1]);
}
printf("program didn't get to here\n");
}
Outputs of ls and this example:
~/workspace/tests/ $ ./ctest bogus_dir
./ctest: cannot access bogus_dir: No such file or directory
~/workspace/tests/ $ ls bogus_dir
ls: cannot access bogus_dir: No such file or directory