execvp behaves weirdly with ls - c

Here is a minimal reproducible example of my issue
#include <unistd.h>
int main (int argc, char *argv[])
{
char *a[] = {"ls", "-l", "~", "..", "-A", NULL};
execvp(a[0], a);
return 0;
}
I expected this to work as it would when I run ls -l ~ .. -A in the shell, but on running the executable after compiling I get the following output
❯ clang main.c -o a
❯ ./a
ls: -A: No such file or directory
ls: ~: No such file or directory
..:
total 0
drwxr-xr-x 3 me staff 96 Sep 1 11:56 test

Related

Running a Cygwin compiled executable with gettext/libintl in MSYS2 shells (cygheap read copy failed)?

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?

Compiling C and sqlite3

I'm having some trouble incorporating sqlite3 into a program I'm writing. I've been scouring the internet over the past few days attempting to find a solution. I'm using the MinGW compiler and have already tried:
Ensuring the C:\MinGW\bin directory is included in both the user and system environment Path variables with no spaces and separated with a semi-colon
Using the command prompt and entering "C:\MinGW\bin\gcc shell.c sqlite3.c -lpthread -ldl" in the same directory of all related files which returns the result "c:/mingw/bin/../lib/gcc/mingw32/5.3.0/../../../../mingw32/bin/ld.exe: cannot find -ldl
collect2.exe: error: ld returned 1 exit status"
Fresh install of MinGW and eclipse
If it helps this is the code I'm testing this with, I can't get the includes to show up as code but they are all in carets in order, iostream, stdio.h, and sqlite3.h
It returns the error "fatal error: sqlite3.h: No such file or directory". I have all of the include files in the same directory as the .cpp source as well.
int main(int argc, char* argv[])
{
sqlite3 *db;
char *zErrMsg = 0;
int rc;
rc = sqlite3_open("text.db", &db);
return 0;
}
#include <stdio.h>
#include "sqlite3.h"
int main(int argc, char* argv[])
{
sqlite3 *db;
char *zErrMsg = 0;
int rc;
rc = sqlite3_open("text.db", &db);
return 0;
}
Compile and test result:
w00343520#wuhy1w001184171 MINGW64 /d/Download/sqlite-amalgamation-3190200/sqlite-amalgamation-3190200
$ mingw32-gcc -o test main.c sqlite3.c -I./
w00343520#wuhy1w001184171 MINGW64 /d/Download/sqlite-amalgamation-3190200/sqlite-amalgamation-3190200
$ ll
total 8485
-rw-r--r-- 1 w00343520 1049089 192 六月 8 10:38 main.c
-rw-r--r-- 1 w00343520 1049089 236938 五月 26 00:15 shell.c
-rw-r--r-- 1 w00343520 1049089 7130198 五月 26 00:15 sqlite3.c
-rw-r--r-- 1 w00343520 1049089 498184 五月 26 00:15 sqlite3.h
-rw-r--r-- 1 w00343520 1049089 30199 五月 26 00:15 sqlite3ext.h
-rwxr-xr-x 1 w00343520 1049089 785640 六月 8 10:38 test.exe*
w00343520#wuhy1w001184171 MINGW64 /d/Download/sqlite-amalgamation-3190200/sqlite-amalgamation-3190200
$ ./test.exe
w00343520#wuhy1w001184171 MINGW64 /d/Download/sqlite-amalgamation-3190200/sqlite-amalgamation-3190200
$ ll
total 8485
-rw-r--r-- 1 w00343520 1049089 192 六月 8 10:38 main.c
-rw-r--r-- 1 w00343520 1049089 236938 五月 26 00:15 shell.c
-rw-r--r-- 1 w00343520 1049089 7130198 五月 26 00:15 sqlite3.c
-rw-r--r-- 1 w00343520 1049089 498184 五月 26 00:15 sqlite3.h
-rw-r--r-- 1 w00343520 1049089 30199 五月 26 00:15 sqlite3ext.h
-rwxr-xr-x 1 w00343520 1049089 785640 六月 8 10:38 test.exe*
-rw-r--r-- 1 w00343520 1049089 0 六月 8 10:41 text.db
w00343520#wuhy1w001184171 MINGW64 /d/Download/sqlite-amalgamation-3190200/sqlite-amalgamation-3190200
$
The test result for shell.c:
w00343520#wuhy1w001184171 MINGW64 /d/Download/sqlite-amalgamation-3190200/sqlite-amalgamation-3190200
$ mingw32-gcc -o sqlite shell.c sqlite3.c -I./
w00343520#wuhy1w001184171 MINGW64 /d/Download/sqlite-amalgamation-3190200/sqlite-amalgamation-3190200
$ ./sqlite.exe
w00343520#wuhy1w001184171 MINGW64 /d/Download/sqlite-amalgamation-3190200/sqlite-amalgamation-3190200
$ ./sqlite.exe --help
Usage: D:\Download\sqlite-amalgamation-3190200\sqlite-amalgamation-3190200\sqlite.exe [OPTIONS] FILENAME [SQL]
FILENAME is the name of an SQLite database. A new database is created
if the file does not previously exist.
OPTIONS include:
-ascii set output mode to 'ascii'
-bail stop after hitting an error
-batch force batch I/O
-column set output mode to 'column'
-cmd COMMAND run "COMMAND" before reading stdin
-csv set output mode to 'csv'
-echo print commands before execution
-init FILENAME read/process named file
-[no]header turn headers on or off
-help show this message
-html set output mode to HTML
-interactive force interactive I/O
-line set output mode to 'line'
-list set output mode to 'list'
-lookaside SIZE N use N entries of SZ bytes for lookaside memory
-mmap N default mmap size set to N
-newline SEP set output row separator. Default: '\n'
-nullvalue TEXT set text string for NULL values. Default ''
-pagecache SIZE N use N slots of SZ bytes each for page cache memory
-scratch SIZE N use N slots of SZ bytes each for scratch memory
-separator SEP set output column separator. Default: '|'
-stats print memory stats before each finalize
-version show SQLite version
-vfs NAME use NAME as the default VFS
w00343520#wuhy1w001184171 MINGW64 /d/Download/sqlite-amalgamation-3190200/sqlite-amalgamation-3190200
$
After fiddling around a bit I realized all I had to do was #include "sqlite3.h" with the sqlite.h file in the source file directory and include the sqlite3.c file in the project tree. I'm using DevC++ and I went to project > add to project and select the sqlite3.c file. Then project > project options > files and select sqlite3.c then uncheck "compile file as C++".

Executable with set-user-ID-on-execution option doesn't set effective uid

Here is a program which shows euid:
$ cat main.c
#include <stdio.h>
#include <unistd.h>
int main(int argc, char** argv) {
printf("euid: %d\n", geteuid());
return 0;
}
$ gcc main.c -o main
$ ls -l main
-rwxr-xr-x 1 scdmb scdmb 6425 Mar 30 14:07 main
Let's set set-user-ID-on-execution option:
$ chmod u+s main
$ ls -l main
-rwsr-xr-x 1 scdmb scdmb 6425 Mar 30 14:07 main
Program executed as user scdmb shows right euid:
$ ./main
euid: 1000
$ id -u scdmb
1000
Let's execute program as other user:
$ id -u jakisuser
1001
$ su jakisuser
Password:
Now euid is the same as uid of user jakisuser:
$ ./main
euid: 1001
Why this set-user-ID-on-execution option doesn't cause that second time effective user id is not 1000 (as file owner) but 1001 (as the one who executes program)? Shouldn't it be the same as owner of file main?
I've just tried this here and your program works perfectly.
What I suspect is happening is that you have apparmor or selinux or something else in the way which is preventing your SUID bit from taking effect. I suggest you disable those and try again.

root command from a 'set-user root' program

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.

Why do I get the error "bash: ./a.out: Permission denied" when I execute a C program in Linux mint 15

I am writing a user ls command code in C. When I compile this code with cc lss.c, an a.out file is created, but then using ./a.out to run, I get an error.
My lss.c:
#include <stdio.h>
#include <stdlib.h>
int main(int argc, char *argv[])
{
char cmdline[100];
if ( argc > 2 )
{
printf(cmdline, "ls %s %s", argv[1], argv[2]);
system(cmdline);
}
return 0;
}
When I compile and run, this is what happens:
$ cd "/media/dilip/New Volume1/c"
$ cc lss.c
$ ./a.out
bash: ./a.out: Permission denied
$
What is the cause of this error?
I think, you are trying to run your program on an NTFS partition, different from the one on which Mint is installed. Try to compile the program in your ext4 partition and generate the a.out there. It should run.
Compile and Run it on the Volume where your linux is installed.

Resources