I'm trying to merge a set of files using C system() call:
int main(int argc, char* argv[]) {
return system("cat output{1,2} > merged.out");
}
The result is:
$ gcc test.c
$ ./a.out
cat: output{1,2}: No such file or directory
It works if I do it directly in bash:
$ ls output{1,2}
output1 output2
$ cat output{1,2}
1,2
3,4
How can I enable parameter expansion in the system() call?
The reason for this is that system uses /bin/sh, which does not expand braces. For instance, try:
/bin/sh -c 'echo cat output{1,2}'
and compare
/bin/bash -c 'echo cat output{1,2}'
If you must, something like
system("/bin/bash -c 'cat output{1,2} > merged.out'");
but why not simply read both files and write the output to merged.out?
system passes the command to /bin/sh -c. If parameter expansion does not work as expected /bin/sh is not linked to /bin/bash on the system. You can explicitely start a bash shell using this:
return system("bash -c \"cat output{1,2} > merged.out\"");
Expansion is a shell duty. Something like `system("/usr/bin/bash -c \"cat output{1,2}\" > merged.out");" should work.
Related
This seems to be a similar issue to the one listed in "cygheap read copy failed ... Win32 error 6" after linking program with gettext · Issue #1794 · msys2/MSYS2-packages · GitHub, but I cannot find a solution for my use case.
I'm working on Windows 10, and below is a bash script, that generates a simple test .c file that uses libintl, and builds it as an executable under Cygwin, while statically linking the Cygwin libintl and libiconv libraries. Simply copy the script and run it with bash test_intl.sh in a Cygwin shell (Cygwin64 Terminal):
test_intl.sh
# example from https://localazy.com/blog/make-multi-language-application-in-c-gettext-localazy
mkdir -p /tmp/testintl/locales/en/LC_MESSAGES
cd /tmp/testintl
cat > testintl.c <<'EOF'
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <libintl.h>
#include <locale.h>
#define _(String) gettext(String)
int main(int argc, char *argv[]) {
int opt;
char *filename = NULL;
int i_flag = 0;
int g_flag = 0;
bindtextdomain ("base", "./locales/");
textdomain ("base");
while ( (opt = getopt(argc, argv, "hi:g:")) != -1 ) {
switch(opt) {
case 'h':
printf(_("\033[1;37mThis application does absolutely nothing.\n\n"));
printf(_("Available options:\n"));
printf(_("-i <file>\tDoes nothing with specified file. \n"));
printf(_("-g <file>\tDoes nothing with specified file, but in \033[0;32mgreen color\033[0;37m.\n"));
break;
case 'i':
filename = optarg;
i_flag = 1;
break;
case 'g':
filename = optarg;
g_flag = 1;
break;
default:
printf(_("Use -h to display help.\n"));
return 0;
}
}
if (!i_flag && !g_flag) {
printf(_("Use -h to display help.\n"));
}
if ((i_flag || g_flag) && !filename) {
printf(_("You must specify a destination file name.\n"));
return 1;
}
if (i_flag) {
printf(_("Doing nothing with %s file...\n"), filename);
printf(_("Done.\n"));
}
if (g_flag) {
printf(_("\033[0;32mDoing nothing with %s file...\n"), filename);
printf(_("Done.\n"));
}
return 0;
}
EOF
set -x
xgettext -k_ -o locales/base.pot --language=C testintl.c
msginit --no-translator --input=locales/base.pot --locale=en_US --output=locales/en/base.po
msgfmt --output-file=locales/en/LC_MESSAGES/base.mo locales/en/base.po
gcc -g -Wall -Wextra -pedantic -Wno-unused-variable -std=c99 testintl.c -o testintl.exe /lib/libintl.a /lib/libiconv.a
./testintl.exe -h
# copy dependent libraries:
cp -a /bin/cygwin1.dll .
set +x
exepath=$(readlink -f ./testintl.exe)
echo "EXE location (cygwin):" $exepath
echo "EXE location (Windows):" $(cygpath -w $exepath)
When I run this in Cygwin shell, the output is:
user#DESKTOP-PC ~
$ bash test_intl.sh
+ xgettext -k_ -o locales/base.pot --language=C testintl.c
+ msginit --no-translator --input=locales/base.pot --locale=en_US --output=locales/en/base.po
Created locales/en/base.po.
+ msgfmt --output-file=locales/en/LC_MESSAGES/base.mo locales/en/base.po
+ gcc -g -Wall -Wextra -pedantic -Wno-unused-variable -std=c99 testintl.c -o testintl.exe /lib/libintl.a /lib/libiconv.a
+ ./testintl.exe -h
This application does absolutely nothing.
Available options:
-i <file> Does nothing with specified file.
-g <file> Does nothing with specified file, but in green color.
Use -h to display help.
+ cp -a /bin/cygwin1.dll .
+ set +x
EXE location (cygwin): /tmp/testintl/testintl.exe
EXE location (Windows): C:\cygwin64\tmp\testintl\testintl.exe
So, the executable clearly works in the Cygwin shell.
I also try running it from the Command Prompt (cmd.exe):
C:\Users\user>C:\cygwin64\tmp\testintl\testintl.exe -h
This application does absolutely nothing.
Available options:
-i <file> Does nothing with specified file.
-g <file> Does nothing with specified file, but in green color.
Use -h to display help.
So, the executable clearly works in the cmd.exe shell.
Now, I try to run this executable from a MSYS2 shell - either MSYS or MINGW64, makes no difference in behavior:
user#DESKTOP-PC 2023-01-15 MINGW64 ~
$ /c/cygwin64/tmp/testintl/testintl.exe -h
0 [main] testintl (19376) child_copy: cygheap read copy failed, 0x800000000..0x8000105A8, done 0, windows pid 19376, Win32 error 6
870 [main] testintl 1423 C:\cygwin64\tmp\testintl\testintl.exe: *** fatal error - couldn't create signal pipe, Win32 error 5
Clearly, the executable does not run under a MSYS2 shell.
Is there some workaround I can do, so this executable also works under a MSYS2 shell?
Consider the following simple C program, which I will compile to a program called "A":
#include <stdio.h>
int main(int argc, char** argv){
putchar('C');
putchar('\n');
}
Now, consider the following bash script:
#!/bin/bash
mkfifo Output1.pipe
mkfifo Output2.pipe
stdbuf -i0 -o0 -e0 ./A > Output1.pipe &
stdbuf -i0 -o0 -e0 ./A > Output2.pipe &
cat Output1.pipe
cat Output2.pipe
The output of this script is C\nC. So far everything is fine.
Now let's consider the following modification the bash script, observing that the C program never reads stdin.
#!/bin/bash
mkfifo Input1.pipe
mkfifo Input2.pipe
mkfifo Output1.pipe
mkfifo Output2.pipe
stdbuf -i0 -o0 -e0 ./A > Output1.pipe < Input1.pipe &
stdbuf -i0 -o0 -e0 ./A > Output2.pipe < Input2.pipe &
cat Output1.pipe
cat Output2.pipe
When this bash script is run, it hangs until output is manually written to Input1.pipe and then Input2.pipe.
What is going on here and is there a way to get it to not hang at this step?
In this setup, your program doesn't even run (AFAIR), because the shell first opens both channels and then the program is started. And opening a reading FIFO hangs until it is opened writing as well.
There is no (easy) way to prevent this.
I'm trying to use GCC in a shell script, but i want to use no input file, but a variable that contain my code.
For now I do :
echo '
#include <stdio.h>
int main(){
int a=1,b;
printf("Donnez un nombre : ");
scanf("%d", &b);
a+=b;
printf("test%d\n",a );
return 0;
}
' > .temp.c
#Entrez le texte ici
gcc .temp.c -o .ex -std=c99
Can I do something like gcc $inputCode -o executable ?
Moreover, if someone know if I can execute this c code without generating any file ?
Thanks !
You can do: echo whatever | gcc -x c -o .ex - but I hardly think it's worth it.
An alternate that may be cleaner [you don't have do either \" or \']. Note that the trap example may not be completely correct, but is probably something you're trying to achieve.
cat << EOF | gcc -x c -o .ex -
int
main(void)
{
return 'a';
}
EOF
trap "rm -f .ex" SIGINT
.ex
rm -f .ex
But, you're still going to have to create an output ELF executable file. Partly because the OS needs the embedded ELF loader (e.g. /lib64/ld-linux-x86-64.so.2) to know how to load the executable.
I've done the "script creates C executable from source" many times and I just create the .c and the executable and just do rm afterwards. I do this in perl where the C text appears after __DATA__ and I do an unlink function call instead of rm
I wish to start a root command from a 'set-user root' program,
so I wrote the following C sample program:
#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <unistd.h>
void main(int argc, char *argv[])
{
if(argc > 2) {
setuid(0);
printf("setuid(0) executed\n");
} else
printf("setuid(0) NOT executed\n");
system(argv[1]);
}
Testing it on Debian 6 (64 bit), I noticed that passing "/bin/sh" as the argument, I always get a ROOT SHELL, even if argc == 2:
$ gcc foo.c -o foo
$ su
Password: *****
# chown root:root ./foo
# chmod 4755 ./foo
# ls -l foo
-rwsr-xr-x 1 root root 6887 11 dic 17.44 foo
# exit
exit
$ ./foo /bin/sh
setuid(0) NOT executed
# exit <<<<< ROOT SHELL
$ ./foo /bin/sh 12345
setuid(0) executed
# exit <<<<< ROOT SHELL
On Slackware 14 (32 bit), it behaves differently:
$ gcc foo.c -o foo
$ su
Password: *****
bash-4.2# chown root:root ./foo
bash-4.2# chmod 4755 ./foo
bash-4.2# ls -l foo
-rwsr-xr-x 1 root root 6292 dic 11 17:53 foo
bash-4.2# exit
exit
$ foo /bin/sh
setuid(0) NOT executed
sh-4.2$ exit <<<<< USER SHELL
exit
$ foo /bin/sh 12345
setuid(0) executed
sh-4.2# exit <<<<< ROOT SHELL
exit
If I give "/usr/bin/dolphin" as argument, there is also a different behaviour.
On Debian I'm not able to get it work:
$ ./foo /usr/bin/dolphin
setuid(0) NOT executed
<unknown program name>(28884)/: KUniqueApplication: Cannot find the D-Bus session server: "Unable to autolaunch when setuid"
<unknown program name>(28883)/: KUniqueApplication: Pipe closed unexpectedly.
On Slackware, it works only if argc == 2, so I cannot start dolphin as root.
Why?
To explain the slightly peculiar setuid behaviour, you need to understand that /bin/sh may actually be bash, and the default behaviour of bash is to drop euid unless it's invoked with -p.
This means that if you invoke bash with -p, then you should see a 'root' like shell:-
natsu ~> id -a
uid=1000(me) gid=1000(me) groups=1000(me),4(adm),15(kmem)
natsu ~> ./foo "/bin/bash -p"
setuid(0) NOT executed
bash-4.2# id -a
uid=1000(me) gid=1000(me) euid=0(root) egid=0(root) groups=0(root),4(adm),15(kmem),1000(me)
Whereas invoked without the -p option yields the observed behaviour:
pshanahan#natsu ~> ./foo /bin/bash
setuid(0) NOT executed
bash-4.2$ id -a
uid=1000(me) gid=1000(me) groups=1000(me),4(adm),15(kmem)
but in reality, you only have effective user id 0, not real user id 0.
getting the GUI to run in this situation... That's another matter altogether; but this should help you understand the behaviour in this case.
Really off the wall question here, but is there a way to compile a string of C code in GCC without any medium to hold that string (eg. a source file)?
Something along the lines of:
$ gcc "#include <stdio.h> int main( void ){ printf('hello world'); return 0;}" -o test
Feels really dirty, but it would be really nice if there was some simple way to do that type of thing.
If you use - as the input file in the command line, gcc reads from standard input. Since there is no file name extension gcc could use to find out the language that should be compiled, it has to be specified with the -x flag:
$ gcc -x c -o tst - <<EOF
> #include <stdio.h>
> int main(void) {
> printf("Hello world\n");
> }
> EOF
$ ./tst
Hello world
I confess to sometimes highlighting code and using:
(cat preamble.hpp; xsel) | g++ -x c++ - && ./a.out
The same works with "-x c" for C.