usage of _execl() function on Windows10 platform - c

_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");

Related

Pass a value from a C variable to an embedded shell script?

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;
}

Running find from a C program to print file name given inode number?

I am trying to print the file name given the inode number. I am using the execlp system call to run the find command. My code is shown below:
#include <sys/mman.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <stdio.h>
#include <stdlib.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
int main(int argc,char *argv[])
{
char str[8];
char *ptr;
ptr=str;
long x=9306140;
snprintf(str,8,"%ld", x);
execlp("find"," ","~"," ","-inum"," ",str,NULL);
}
But I get an error: Invalid argument '9306140' to -inum.
Could someone please help?
As noted in comments, you don't want the " " (space) arguments in the execlp() argument list. The shell takes a string with spaces separating the arguments, but it treats what's between the spaces as words that are passed to the command; it doesn't ordinarily pass the spaces to the command. (That's a simple and sufficient explanation for this exercise; there are caveats and weasel-words galore that could be added.)
The shell also expands ~ to match the value in the $HOME environment variable (in contrast to ~user which gets the home directory of user from the password file — they're usually, but not necessarily, the same).
You also have little margin for error in the size of string you've allocated for the number. Frankly, though, you should simply use a string. All these changes lead to:
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
int main(void)
{
const char *home = getenv("HOME");
const char inode[] = "9306140";
execlp("find", "find", home, "-inum", inode, (char *)NULL);
fprintf(stderr, "failed to execute 'find' command\n");
return(EXIT_FAILURE);
}
Note the repeated "find"; the first is the name of the file to be executed after searching along the path; the second is the value to be provided as argv[0]. You could put "hypochondriac" as the second occurrence and it is likely that find would work the same, at worst reporting its error messages as coming from the program 'hypochondriac'.
The next step would be to take the inode number from a command line argument:
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
int main(int argc, char **argv)
{
if (argc != 2)
{
fprintf(stderr, "Usage: %s inode\n", argv[0]);
exit(EXIT_FAILURE);
}
const char *home = getenv("HOME");
const char *inode = argv[1];
execlp("find", "find", home, "-inum", inode, (char *)NULL);
fprintf(stderr, "%s: failed to execute 'find' command\n", argv[0]);
return(EXIT_FAILURE);
}
The step after that would be to handle multiple inode values; at that point, you use execvp() instead of execlp(), though (or, if you're desparate and lazy, you loop and fork() and execlp() once per inode number, but that's slamming your system for no good reason at all).

How to reproduce "2 No such file or directory" in C

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

Setting Immutable Flag using ioctl() in C

I have attempted to make a script that creates a file and then sets it as immutable similar to the chattr +i command for linux. The script compiles (with gcc), runs and the file is created. However the file itself is not immutable and can be removed with a simple rm -f. I have attempted to stacktrace where chattr is called and I found a function called ioctl. I then used what little information I could gather and came up with what I have below. I narrowed it down from ext2_fs.h but it just doesn't seem to work. I've clearly overlooked something.
Updates to previous entry: Compiles but returns -1 on ioctl() function. Bad address shown with perror().
#include <stdio.h>
#include <stdlib.h>
#include <sys/stat.h>
#include <sys/ioctl.h>
#include <linux/fs.h>
int main()
{
FILE *fp;
char shovel[16] = "I have a shovel!";
fp = fopen("/shovel.txt", "w+");
fwrite(shovel, sizeof(shovel[0]), sizeof(shovel)/sizeof(shovel[0]), fp);
ioctl(fileno(fp), FS_IOC_SETFLAGS, 0x00000010);
fclose(fp);
}
Any help appreciated.
You are using the right ioctl command, but you're passing it the wrong arguments.
The manpage for ioctl_list(2) shows that FS_IOC_SETFLAGS expects to receive a pointer to int (an int *), yet you're passing it an integer literal (hence the Bad Address error).
The fact that you don't to any error checking whatsoever is also not helping.
The correct flag to pass to FS_IOC_SETFLAGS is a pointer holding the value EXT2_IMMUTABLE_FL, which is defined in ext2fs/ext2_fs.h (some older / different Linux distributions seem to have it under linux/ext2_fs.h), so you'll need to #include <ext2fs/etx2_fs.h>. Make sure to install e2fslibs-dev (and probably you'll need linux-headers too).
This code is working:
#include <stdio.h>
#include <stdlib.h>
#include <sys/stat.h>
#include <sys/ioctl.h>
#include <linux/fs.h>
#include <ext2fs/ext2_fs.h>
int main()
{
FILE *fp;
char shovel[16] = "I have a shovel!";
if ((fp = fopen("shovel.txt", "w+")) == NULL) {
perror("fopen(3) error");
exit(EXIT_FAILURE);
}
fwrite(shovel, sizeof(shovel[0]), sizeof(shovel)/sizeof(shovel[0]), fp);
int val = EXT2_IMMUTABLE_FL;
if (ioctl(fileno(fp), FS_IOC_SETFLAGS, &val) < 0)
perror("ioctl(2) error");
fclose(fp);
return 0;
}
Remember to run this as root.
UPDATE:
As Giuseppe Guerrini suggests in his answer, you might want to use FS_IMMUTABLE_FL instead, and you won't need to include ext2_fs.h:
#include <stdio.h>
#include <stdlib.h>
#include <sys/stat.h>
#include <sys/ioctl.h>
#include <linux/fs.h>
int main()
{
FILE *fp;
char shovel[16] = "I have a shovel!";
if ((fp = fopen("shovel.txt", "w+")) == NULL) {
perror("fopen(3) error");
exit(EXIT_FAILURE);
}
fwrite(shovel, sizeof(shovel[0]), sizeof(shovel)/sizeof(shovel[0]), fp);
int val = FS_IMMUTABLE_FL;
if (ioctl(fileno(fp), FS_IOC_SETFLAGS, &val) < 0)
perror("ioctl(2) error");
fclose(fp);
return 0;
}
The main problem is that the ioctl wants a pointer to the mask, not a direct constant. You have to define a int variable, store the mask (0x10) in it and pass its address as third argument of ioctl.
Also, I'd add some hints:
other programs to change attributes are used to use low-level I/O directly (open, close...). Also, the file is usually opened with O_RDONLY.
Use FS_IMMUTABLE_FL istead the raw constant.
Get the current attribute mask first (FS_IOC_SETFLAGS) and mask it with the new flag, so other settings are not lost by the service.

seteuid() not working. Reason?

I'm completely new to C and I use it very rarely. This time i need it for a university project. I have to write a small c app that tests some modifications we made on the Linux kernel (on the scheduler).
Inside the script I'd like to switch to another user to see the distribution of CPU times among the different users. So I start my small C prog with root rights (i.e. with sudo ./myapp). Inside the prog - after I performed some operations which need root rights - I would like to switch back to another uid by calling seteuid(1000) or setuid(1000) where 1000 is the ID of an existing user (the one I used to log on). However the call doesn't seem to have any effect, it doesn't throw any exception neither.
Here's a sample I wrote, just to test the uid switching:
#define _POSIX_SOURCE
#include <pwd.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sched.h>
#include <unistd.h>
#include <string>
#include <time.h>
using namespace std;
int main(int argc, char *argv[])
{
int uid;
struct passwd *p;
if ((p = getpwuid(uid = getuid())) == NULL){
perror("getpwuid() error");
exit(1);
}
printf("***************************************\n");
printf("Executing user: %s (%d)\n", p->pw_name, p->pw_uid);
printf("***************************************\n");
seteuid(1000);
if ((p = getpwuid(uid = getuid())) == NULL){
perror("getpwuid() error");
exit(1);
}
printf("***************************************\n");
printf("Executing user: %s (%d)\n", p->pw_name, p->pw_uid);
printf("***************************************\n");
return 0;
}
Does anyone know why it won't work?? Any help is highly appreciated! Thx
//Edit:
Corrected code as mentioned by chsh
I think it is working just fine, there's just a problem with the logic in the code because you're capturing the value of getuid() into the passwd struct, and then just displaying it twice without retrieving it again after calling seteuid().

Resources