Troubles passing arguments through execlp function - C - c

i'm using a given md5 function who calculates a file hash when you feed it with a file address. Thing is that i need to execute this program using fork() and then load it using any exe...() function(im trying with execlp()) but when i do it and i pass the single argument i need to calculate the hash it fails. I tried running md5 program manually with the exact argument i use in execlp and it doesn't fail so i'm just assuming it must be something wrong with execlp parameters. Here's an example i made to explain the scenario:
#include <stdio.h>
#include <sys/types.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/wait.h>
int main(){
pid_t cpid;int status;
cpid = fork();
if(cpid < 0){
printf("Error fork\n");
exit (EXIT_FAILURE);
}else if (!cpid){
if (execlp("./hashMD5/me/md5","md5","testfile.a",(char*)NULL) == -1){
printf("Error: Loading process\n");
exit(EXIT_FAILURE);
}
}else{
waitpid(cpid,&status,0);
}
exit (EXIT_SUCCESS);
}
when i use this i got an error in terminal:
$testfile.a can't be opened
but if i manually execute the md5 program with the exactly same argument i got the correct execution.
What's wrong? Help!

the following proposed code:
cleanly compiles
documents why each header file is included
uses a proper call to execl() rather than execlp() because execl() expects the first parameter to be a complete path while execlp() expects the first parameter to be just a file name.
properly formats the code, for ease of readability and understanding
properly handles calling execl() and possible failure of that call
properly passes error messages to stderr rather than stdout, using perror(), so the reason the system thinks the error occurred is also displayed on stderr.
And now, the proposed code:
#include <stdio.h> // perror()
#include <sys/types.h>
#include <stdlib.h> // exit(), EXIT_FAILURE, EXIT_SUCCESS
#include <unistd.h> // fork(), execlp()
#include <sys/wait.h> // waitpid()
int main( void )
{
pid_t cpid;int status;
cpid = fork();
if(cpid < 0)
{ // error
perror("Error fork\n");
exit (EXIT_FAILURE);
}
else if (!cpid)
{ // child
execl("./hashMD5/me/md5","md5","testfile.a", NULL);
perror("Error: Loading process\n");
exit(EXIT_FAILURE);
}
else
{ // parent
waitpid(cpid,&status,0);
}
exit (EXIT_SUCCESS);
}

I finally solved the problem. I appreciate the improvements people gave me, i'm always happy to learn new things!
The problem was with the argument itself: Even when you use execlp to create a brand new process the path of the argument remains relative to parent process, that's why was not working. After several headaches i finally realized that. Thanks to everyone!

Related

Is it possible for a program to capture SIGTERM generated by the exit system call?

The program I have is as follows:
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <signal.h>
int main()
{
struct sigaction new_sa;
struct sigaction old_sa;
sigfillset(&new_sa.sa_mask);
new_sa.sa_handler = SIG_IGN;
new_sa.sa_flags = 0;
int input;
if (sigaction(SIGTERM, &new_sa, &old_sa) == 0 && old_sa.sa_handler != SIG_IGN) {
new_sa.sa_handler = NULL;
sigaction(SIGTERM, &new_sa, 0);
}
printf("Pgm is running\n");
while (1) {
printf("Enter input\n");
scanf("%d", &input);
if (!input) {
/* I actually call a libraries API which calls exit()
* Just calling exit here for simpilicity */
exit(1);
}
}
}
I want to handle/ignore SIGTERM generated by exit system call. Is it possible?
There is no way for me to avoid calling exit since its actually a library call which is trying to exit the program which i want to avoid.
You can certainly catch SIGTERM. But that's not the problem here. You want to override the exit() call.
This is not possible in any portable or standard compliant way. The exit() is one of the functions that's defined to not return to its caller. Typically, this is done using the __attribute__((noreturn)) in gcc and C11 has introduced the macro _Noreturn for the same purpose.
Attempting to return from such function, like exit(), is undefined behaviour.
There are few options, I can think of:
Compile and replace with your function: gcc -Dexit=not_exit file.c
Write a hook function for exit(). See here for an example. Implementing a hook function may not work at all since this noreturn has existed on most libc implementations before C11's _Noreturn.
Use GNU's ld as suggested by #evading. I believe this equivalent to the above but the linker does half of the work for you.
Modifying <stdlib.h> to remove the _Noreturn (or its equivalent) attribute for the exit() function might make it work. None of these is guaranteed to work. We are already well into the UB land.
Other option is to an install atexit() handler, which might be useful if you want to do something before exit().
A saner approach would be to modify the library if you to not call exit() but instead return a error code. In my opinion, either the library is badly designed that it randomly exits on its own or probably there's a good reason that the library exits (due to some unrecoverable error) and your application is not supposed to continue any further, which you are attempting to do.
Looking at the glibc source for exit it looks like it isn't possible. But it might be if you're using another C std library.
You can do stuff at_exit but you can't prevent it.
[edit]
Everything below here is apparently not applicable for exit for the reasons in this question.
If you use gnu ld it might be possible to override __run_exit_handlers, or exit for that matter, using the gnu ld --wrap option but I havn't tried it.
If you can use gnu ld you could do --wrap exit and then implement __wrap_exit() in your code. If you want to call exit after this you can access it through __real_exit().
This is a gnu ld feature and I'm not sure how universally available it is.
A possibility is to run the library call in a child process with fork. This does not prevent the call to exit but might be a workaround if you want to handle the error yourself.
Following a tutorial Fork, Exec and Process control. I use pipes to send the result of the library call back if the call is successful.
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/wait.h>
int main(){
int pipefd[2];
pipe(pipefd); //Create pipe for communication
pid_t pid = fork();
if (pid == 0){ //Child process
close(pipefd[0]); // close the read-end of the pipe,
printf("Run library here\n");
// exit(3); if failed
int val=4; //Result of library call send to parent
write(pipefd[1], &val, sizeof(val));
close(pipefd[1]); // close the write-end of the pipe
exit(EXIT_SUCCESS);
}
else if (pid < 0){
printf("Failed to fork\n");
}
else{//Parent process
close(pipefd[1]);
printf("Parent process\n");
int status=0;
int pid=wait(&status);
printf("The pid %d finished with status %d\n",pid,status);
if (status==EXIT_SUCCESS){//The library call was successful
int val=2;
read(pipefd[0],&val,sizeof(int)); //Read data from pipe and do something with it
printf("Value %d received\n",val);
}
close(pipefd[0]);
}
return 0;
}

How can I use execl() function or other kinds of exec() functions to perform echo command?

I have a question, I used the following program(fork() functions) to create a child process to overload another program using execl(). If I want to use echo command in the execl() functions or other kinds of exec() functions ,what should I do? I use following program, but it failed! the terminal gave me a warning:echo: cannot access hello world!: No such file or directory
this is parent!
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/wait.h>
int main()
{ pid_t childpid;
childpid=fork();
if(childpid==-1){
perror("failed to fork");
return 1;
}
if(childpid==0)
{
execl("/bin/ls","echo","hello world!",NULL);
perror("child failed to exec");
return 1;
}
if(childpid!=wait(NULL)){
perror("parent failed to wait due to signal or error");
return 1;
}
sleep(5);
printf("this is parent!\n");
return 0;
}
The command you are executing is:
/bin/ls "echo" "hello world!"
What you probably want to execute is (assuming you are using bash):
/bin/bash -c 'echo "hello world!"'
So use:
execl("/bin/bash","-c","echo \"hello world!\"",NULL);
And you probably want to check for errors before using perror.
Edit:
As per EOF's reccomendation you should probably use system call rather than exec. It handles creating the subprocess for you, and allows you to focus on the task at hand (namely invoking a shell command). The possible disadvantage is that it waits for the subprocess to die before continuing, but that's most likely not an issue (not in this case, anyway). It also ignores certain signals (SIGINT and SIGQUIT) which might not be desirable, depending on how you design your program.

What is a child process? And how do I start it? (Linux, C)

I'm not familiar with C at all.
How do I start a child process? This child process is going to execute the specified command with a call to execve(). It will try to search among the file directory specified in the environment variable PATH after the command can be
found as executable file.
I've done this so far:
//Do commands
pid_t childId;
// Fork the child process
child_id = safefork.c(); //can't use fork();
safefork.c
Code provided by the tutor; do not damn the messenger!
#include <stdlib.h>
#include <sys/types.h>
#include <unistd.h>
#include <sys/errno.h>
extern int errno;
#define MAX_PROCESSES 6
static int n_processes(void)
{
return system("exit `/bin/ps | /store/bin/wc -l`")/256;
}
pid_t safefork(void)
{
static int n_initial = -1;
if (n_initial == -1) /* Første gang funksjonen kalles: */
n_initial = n_processes();
else if (n_processes() >= n_initial+MAX_PROCESSES) {
sleep(2);
errno = EAGAIN;
return (pid_t)-1;
}
return fork();
}
Fixing your code
In your code, get the name of the variable spelled consistently (child_id is not the same as childId).
pid_t child_id = simplefork();
if (child_id < 0)
{
...handle error...
}
else if (child_id == 0)
{
...do childish code - execve() etc...
}
else
{
...do parental code - waitpid() etc...
}
Note that the fork() call within the simplefork() function that you're given to use is responsible for creating the new process. That's all it takes; that's the way it's done for all processes except the very first process.
Why not fork()?
What do you mean by "can't use fork()"? The main alternative mechanism is vfork(), which is a very restricted variant of fork() (do not use it); or maybe you could use posix_spawn() or posix_spawnp() — which are incredibly complex alternatives. I don't think there are any other options.
After forking, you might be able to use execvp() instead of execve() — it will do the path search for you. Unless, of course, the purpose of the exercise is to implement execvp() in terms of execve().
Your code uses the notation safefork.c(), but that is not usually correct in C; I could devise a structure type that would make it work, but it probably isn't what you meant.
We got another file called safefork.c — we are not allowed to use fork, only safefork which is already given.
[…before the code was posted]
OK; that's very curious. Presumably, you got a header safefork.h which declares whatever function you're supposed to use (perhaps extern pid_t safefork(void);), and the file safefork.c which does something to wrap around fork(). 'Tis odd: I don't think fork() is a dangerous function. I'd be curious to see what the 'safe fork' does, but I'm sceptical that it is significantly safer than the standard fork function. (I suppose it could does some things like fflush(0) before invoking fork(), or do an error exit if the fork() fails, but that's pushing the envelope.)
[…after the code was posted]
A critique of the code for safefork(), which I fully recognize is not your own code but code that is given to you to use.
The code for safefork() is an abomination. It runs a shell via system() which runs ps and wc to find out how many processes you currently have running, and goes to sleep for 2 seconds if you can't do the fork() because there are too many processes running (more than 6, maybe including the 3 that the safefork() is running!) and then returns "I failed". Someone needs their head seeing to (and no, that isn't you; it is the author of the code).
Oh, and extern int errno; is incorrect; the only safe way to declare errno is by #include <errno.h>. Negative marks to the teacher for that blunder. It is not a good idea to #include <sys/errno.h>; #include <sys/types.h> is not often needed in modern POSIX — from POSIX 2008 onwards at any rate; it may have been unnecessary before that). In the context of the safefork.h header, making it self-contained does require #include <sys/types.h>.
Even assuming that safefork() is a good idea (it isn't), it should be implemented as shown below.
safefork.h
#ifndef SAFEFORK_H_INCLUDED
#define SAFEFORK_H_INCLUDED
#include <sys/types.h> // pid_t
extern pid_t safefork(void);
#endif
safefork.c
#include "safefork.h"
#include <errno.h>
#include <stdlib.h>
#include <unistd.h>
#define MAX_PROCESSES 6
static int n_processes(void)
{
return system("exit `/bin/ps | /store/bin/wc -l`") / 256;
}
pid_t safefork(void)
{
static int n_initial = -1;
if (n_initial == -1)
n_initial = n_processes();
else if (n_processes() >= n_initial+MAX_PROCESSES)
{
errno = EAGAIN;
return (pid_t)-1;
}
return fork();
}

execl return - Ubuntu

My question is: after finishing the execution of the new process image, the function
execl()
would return the execution to the caller process or to the father process?
When using one of the exec family of functions, you do not expect the function to return at all. The program counter begins at the first instruction of the binary image that replaced the calling process.
From the Darwin man page:
If any of the exec() functions returns, an error will have occurred.
The return value is -1, and the global variable errno will be set to
indicate the error.
There was a comment asking about the following, but it was deleted:
If you are in a child process, and execl succeeds, then the child process is replaced by the new binary. If it fails, then control returns to that child process (the caller). There's no strict relationship between fork and exec, if that's what you're asking. If you are in a child process, and exec fails, then you have a "forked" child process, which is a copy of the original parent process. At this point you probably want to print some error message and exit from the child process.
If you want to know why it failed, you can use the following pattern:
if (execl(...)) {
perror(NULL);
exit(errno);
}
For example, try running this program, the error message will indicate how to fix the program:
#include <errno.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
int main (const int argc, char * const argv[]) {
if (execl("ls", "ls", "-la", NULL)) {
perror(NULL);
exit(errno);
}
return 0;
}
The solution, use execlp instead of execl in this case.

How to code shell '&' in C code?

After a long time of researching for my problem, I have really no idea how I can solve it.
My question is that I need the C source code for something like this:
ls &
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/wait.h>
int main(void) {
int new_pid;
int status;
new_pid = fork();
if (new_pid == 0) {
execlp("ls", "ls", "-l", NULL);
} else {
waitpid(new_pid, &status, 0);
}
return 0;
}
If I code it like this, 'ls -l' will be executed, but it wasnt forked to the background.
It is just an example 'ls -l', it could also be 'xournal &;', 'libreoffice &' or something like this.
My main problem is that I have no idea how to code '&' in C.
Can anyone please provide me a tip or even a solution for this?
When you execute another program, you need to call these functions:
new_pid = fork();
exec(...); //in the child only
If you want to wait until that new process ends (i.e. not specifying the & ) you call
waitpid(new_pid, ...);
That way, your shell blocks until the process you launced is finished.
If you don't want to wait, but just continue operating your shell (i.e. specifying the &) you simply do not call waitpid().
Use system("ls &").
It'd help if you explained why you wanted to run something in the background.

Resources