I want to execute a C program in Linux using fork and exec system calls.
I have written a program msg.c and it's working fine. Then I wrote a program msg1.c.
When I do ./a.out msg.c, it's just printing msg.c as output but not executing my program.
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h> /* for fork */
#include <sys/types.h> /* for pid_t */
#include <sys/wait.h> /* for wait */
int main(int argc,char** argv)
{
/*Spawn a child to run the program.*/
pid_t pid=fork();
if (pid==0)
{ /* child process */
// static char *argv[]={"echo","Foo is my name.",NULL};
execv("/bin/echo",argv);
exit(127); /* only if execv fails */
}
else
{ /* pid!=0; parent process */
waitpid(pid,0,0); /* wait for child to exit */
}
return 0;
}
argv[0] contains your program's name and you are Echo'ing it.
Works flawlessly ;-)
/bin/echo msg.c will print msg.c as output if you need to execute your msg binary then you need to change your code to execv("path/msg");
your exec executes the program echo which prints out whatever argv's value is;
furthermore you cannot "execute" msg.c if it is a sourcefile, you have to compile (gcc msg.c -o msg) it first, and then call something like exec("msg")
C programs are not executables (unless you use an uncommon C interpreter).
You need to compile them first with a compiler like GCC, so compile your msg.c source file into a msg-prog executable (using -Wall to get all warnings and -g to get debugging info from the gcc compiler) with:
gcc -Wall -g msg.c -o msg-prog
Take care to improve the msg.c till you get no warnings.
Then, you might want to replace your execv in your source code with something more sensible. Read execve(2) and execl(3) and perror(3). Consider using
execl ("./msg-prog", "msg-prog", "Foo is my name", NULL);
perror ("execl failed");
exit (127);
Read Advanced Linux Programming.
NB: You might name your executable just msg instead of msg-prog ....
Related
Think of this as a continuation of the good advice here:
https://stackoverflow.com/a/56780616/16739703
except that I am hoping not to modify the child process.
Edit: I have written code which minimises to:
#include <errno.h>
#include <stdio.h>
#include <fcntl.h>
#include <stdlib.h>
#include <unistd.h>
int main(int argc, char *argv[], char *envp[]) {
int init_flags=fcntl(0, F_GETFL, 0);
if (fcntl(0, F_SETFL, init_flags | O_ASYNC)) {
perror("fcntl...F_SET_FL....O_ASYNC");
exit(1);
}
if (fcntl(0, F_SETOWN, getpid())) {
perror("fcntl...F_SETOWN...)");
exit(1);
}
if (execve(argv[1], argv+1, envp)) {
perror("execve");
exit(1);
}
return 1;
}
and this makefile:
all: morehup
CFLAGS=-g -D_GNU_SOURCE
LDFLAGS=-g
so that, with this procedure:
parent> export TMPDIR="$(mktemp -d)"
parent> mkfifo $TMPDIR/fifo
parent> sh
# you get a new shell, probably with a different prompt
parent> exec 7<>$TMPDIR/fifo
# must be both input and output, or the process stalls
child> TMPDIR=... # as other shell
child> ./morehup <$TMPDIR/fifo /bin/sh -c "while true; do date; sleep 5; done"
# you get a list of dates
parent> exit
child> I/O possible # followed by a prompt, with no more dates
the kernel will kill the child when the parent exits.
The more configurable version is here:
https://github.com/JamesC1/morehup/blob/main/morehup.c
I have two questions:
What are the chances of adding modest amounts of code, so that this will mostly work for most of the common *nix?
Is there a posix utility that already does something like this? ie am I reinventing the wheel, and if so, what is it called?
This is my program code:
#include <unistd.h>
#include <stdio.h>
#include <time.h>
#include <stdlib.h>
#include <sys/types.h>
void function() {
srand(time(NULL));
while(1) {
int n = rand();
printf("%d ", n);
//sleep(1);
}
}
int main() {
pid_t pid;
pid = fork();
if (pid == 0) {
function();
}
}
With the sleep line commented out (as in the code above) the program works fine (i.e. it prints a bunch of random numbers too fast to even see if they are actually random), but if I remove the comment the program doesn't print anything and exits (not even the first time, before it gets to the sleep), even though it compiles without warnings or errors with or without the comment.
but if I remove the comment the program doesn't print anything and exits
It does not print, but it does not really exit either. It will still be running a process in the background. And that process runs your infinite while loop.
Using your code in p.c:
$ gcc p.c
$ ./a.out
$ ps -A | grep a.out
267282 pts/0 00:00:00 a.out
$ killall a.out
$ killall a.out
a.out: no process found
The problem is that printf does not really print. It only sends data to the output buffer. In order to force the output buffer to be printed, invoke fflush(stdout)
If you're not flushing, then you just rely on the behavior of the terminal you're using. It's very common for terminals to flush when you write a newline character to the output stream. That's one reason why it's preferable to use printf("data\n") instead of printf("\ndata"). See this question for more info: https://softwareengineering.stackexchange.com/q/381711/283695
I'd suspect that if you just leave your program running, it will eventually print. It makes sense that it has a finite buffer and that it flushes when it gets full. But that's just an (educated) guess, and it depends on your terminal.
it prints a bunch of random numbers too fast to even see if they are actually random
How do you see if a sequence of numbers is random? (Playing the devils advocate)
I believe you need to call fflush(3) from time to time. See also setvbuf(3) and stdio(3) and sysconf(3).
I guess that if you coded:
while(1) {
int n = rand();
printf("%d ", n);
if (n % 4 == 0)
fflush(NULL);
sleep(1);
}
The behavior of your program might be more user friendly. The buffer of stdout might have several dozens of kilobytes at least.
BTW, I could be wrong. Check by reading a recent C draft standard (perhaps n2176).
At the very least, see this C reference website then syscalls(2), fork(2) and sleep(3).
You need to call waitpid(2) or a similar function for every successful fork(2).
If on Linux, read also Advanced Linux Programming and use both strace(1) and gdb(1) to understand the behavior of your program. With GCC don't forget to compile it as gcc -Wall -Wextra -g to get all warnings and debug info.
Consider also using the Clang static analyzer.
I'm currently trying to change the process name of a process so I can read the more easily with htop, top, .... I want to LD_PRELOAD this code into another process so it gets renamed by an environemt variable.
I found a lot of stuff in the internet, but nothing works:
prctl(PR_SET_NAME, "Test");
This does not work because htop is not honoring the name.
Nginx setproctitle (Link) doesn't work as well, because it strips the parameters (which are needed by the process).
I tried everything I found and now I'm out of ideas.
Is this even possible in linux? And how?
Just run your program by shell script or your program through exec and pass desired name as argv[0]:
#/bin/bash
exec -a fancy_name a.out ...
or C/C++:
execl( "./a.out", "fancy_name", ... );
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#define NEW_NAME "hello_world"
int main(int argc, char **argv) {
if(strcmp(argv[0], NEW_NAME)) {
argv[0] = NEW_NAME;
execv("/proc/self/exe", argv);
fputs("exec failed", stderr);
return 1;
}
while(1) // so it goes to the top
;
}
Why does a process that has gone into seccomp mode always get killed on exit?
$ cat simple.c
#include <stdio.h>
#include <stdlib.h>
#include <linux/prctl.h>
int main( int argc, char **argv )
{
printf("Starting\n");
prctl(PR_SET_SECCOMP, 1);
printf("Running\n");
exit(0);
}
$ cc -o simple simple.c
$ ./simple || echo "Returned $?"
Starting
Running
Killed
Returned 137
From the man page, under PR_SET_SECCOMP, the only allowed system calls are read, write, exit, and sigreturn.
When you call exit(0) in the standard library (in recent Linux), you call the exit_group system call, not exit. This is not allowed, so you get a SIGKILL.
(You can see this if you strace the process...)
I'm supposed to create a linux shell using C. Below is my code:
#include <stddef.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/wait.h>
#define SHELL "/bin/sh"
#include "extern.h"
int mysystem (char *command)
{
int status;
pid_t pid;
pid = fork ();
if (pid == 0)
{
execl (SHELL, SHELL, "-c", command, NULL);
_exit (EXIT_FAILURE);
}
else if (pid < 0)
status = -1;
else
if (waitpid (pid, &status, 0) != pid)
status = -1;
return status;
}
Everything is right when I test the code using different commands like "ls", "man", etc. but when I use notepad to create a testfile containing the following:
echo "hello"
exit 2
the return code come out to be 512 when it's supposed to be just 2.
Can anyone help me fix my code?
status is not the exit code; it contains other information as well. Normally the return value is in bits 8-15 of status, but you should be using the macros in wait.h to extract the return value from status in a portable way.
Note that 512 is 2<<8.
Make sure you're using the macros like WIFEXITED and WEXITSTATUS on your status value. See your operating system's man page for waitpid. Here is a description of the POSIX requirements on waitpid.
By notepad do you mean you're using a Windows program to create a Unix shell script? That doesn't work because you end up with CRLF at the end of each line instead of LF. Try the "dos2unix" command on the script to convert it to Unix format and then run it.
I assume you're aware that code is already available in the system() library call? Judging by your function name, I'd guess you're just trying to learn how to do it with system calls.
Try enclosing your command string you supply to /bin/sh with quotes, because otherwise the space character makes /bin/sh think you are supplying another option to the shell itself, not to the command you are calling. For example, try this in a terminal:
/bin/sh -c exit 2
echo $?
and
/bin/sh -c "exit 2"
echo $?
The first one gives 0, and the second one gives the desired 2.