I have a C program. I noticed that you can't put 2 execl's in it.
The code:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/types.h>
#include <unistd.h>
int main()
{
pid_t fork(void);
int system(const char *command);
execl("/bin/sh", "sh", "-c", "kdialog --warningcontinuecancel
\"Make sure to include: \n \n 1. py_lcd folder \n 2. 4x20
Raspberry Pi LCD Display \n 3. Python 2.7.12 to be installed \n
\n If you are missing something, kill the program process and
get them.\"", (char *) 0);
sleep(1);
execl("/bin/sh", "sh", "-c", "kdialog --msgbox \"Setting up files...\" --title \"Installing...\"", (char *) 0);
return(0);
}
Can someone help me if there is a way to bypass this or if i am making a mistake???
The exec family of functions don't return when they succeed. They replace the running process with the one being execed. If you want to run a program in a child process (with full control, unlike system), you need to use fork + exec + wait (or perhaps posix_spawn).
Anything written after execl is a deadcode. The main purpose of execl is to re-use the current process information for a new process to improve performance. You will be using sharing the same structures of process information(pid, stack, heap etc.) of the current process where execl is executed.
I found an answer myself. There is a system() command which works the exact same but you are able to insert it anywhere in the code without problems
Related
I am looking for a ptrace() call to observe a process until the process exits.
I have this which compiles with gcc / cc on OSX:
#include <sys/types.h>
#include <stdlib.h>
#include <sys/wait.h>
#include <stdio.h>
#include <sys/ptrace.h>
int main(int argc, char *argv[]) {
pid_t pidx = atoi(argv[1]);
printf("pid = %jd\n", (intmax_t) pidx);
ptrace(PT_ATTACHEXC, pidx, 0, 0);
wait(NULL);
}
However, even with a valid/existing pid, this program will still exit immediately. I am trying to only exit this program after pidx dies.
Is this possible somehow?
Ideally I want something that works on both OSX and Linux.
Your problem is probably that the wait call returns immediately, because the traced "inferior" process is suspended, you know, waiting for you to debug it. You're going to need some kind of loop in which you make ptrace requests to inspect the child and then resume execution, and then call wait again to wait for it to suspend on the next breakpoint or whatever. Unfortunately the debugger API is extremely non-portable; you will have to write most of this program twice, once for OSX and once for Linux.
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
;
}
I am trying some exec family functions in C and I have few questions concerning environment variables, here's my code:
find.c
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
int main(int argc, char *argv){
char *line = getenv("LINE");
char *target = getenv("TARGET");
if(!line || !target){
printf("LINE or/and TARGET not found\n");
return 1;
}
if(strstr(line,target))
puts(line);
return 0;
}
process.c
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
int main(){
putenv("LINE=Hello world");
putenv("TARGET=Hello");
execl("./find","./find",NULL);
return 0;
}
output on "gcc process.c -o process && ./process"
Hello world
Quick explanation of the code.
find.c needs to read two environment variables and check if the TARGET variable value is a substring of the LINE variable value. If so, then print the LINE variable value.
process.c replace itself by executing find.c.
Questions
Knowing that the correct way of doing this is using execle, why did the program process.c work using execl and putenv ? In other words, creating environment variable in a process that get replaced doesn't replace the environment variable as well if not passed via execle ?
Does forking a process has the same answer to the above question ? So forking a process copies, replace or share the environment variables ?
Thank you
Knowing that the correct way of doing this is using execle, why did the program process.c work using execl and putenv?
This is explained in the man page:
The execle() and execvpe() functions allow the caller to specify the environment of the executed program via the argument envp. [...] The other functions take the environment for the new process image from the external variable environ in the calling process.
Note that environ is what's modified by putenv.
Does forking a process has the same answer to the above question ?
Forking duplicates the environment variables. From the man page:
The new process, referred to as the child, is an exact duplicate of the calling process, referred to as the parent, except for the following points:
[... list of points, none of which refer to environment variables ...]
I've been using a combination of fork() and exec() to execute some external command on linux, however, the code seems to fail whenever I try to execute /usr/bin/firefox which is a symbolic link to a real binary.
Does anyone know how to solve this problem? I've tested with other programs (which really are executable binaries and not symlinks to them) and it works.
Here's the code from the program:
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <string.h>
#include <errno.h>
int main(int argc, char **argv) {
pid_t pid;
// this was the old line:
// char *parmList[] = {"", "index.html", NULL};
// and this is the one that solves the problem:
char *parmList[] = {"firefox", "index.html", NULL};
int a;
if ((pid = fork()) == -1)
perror("fork failed");
if (pid == 0) {
a = execvp("/usr/bin/firefox", parmList);
fprintf(stdout, "execvp() returned %d\n", a);
fprintf(stdout, "errno: %s (%d).\n", strerror(errno), errno);
}
else {
waitpid(pid, 0, 0);
}
return 0;
}
Edit: I updated the code to include the answer and changed the topic's title because the problem really didn't seem to be due to symbolic links at all. Thanks everyone.
You might want to add some code right after the execvp to output some diagnostic (i.e. check errno, print something meaningful ;)).
You could also try to analyze it w/o source modification using strace or gdb for that matter.
See also: execve.
Update as follow-up from the comments
Firefox is not happy with argv[0] being empty, which is what argList looked like, unfortunately.
Lessons learned: Be thoroughly aware of what you pass as argv to the program you execute. :)
Does Firefox insist on having a non-empty argv[0]? You should normally pass the name of the command (either just "firefox" or "/usr/bin/firefox") to the command, but you are not doing so.
[...going to check the deeper comments above - and it seems this is the correct diagnosis, but 21 minutes or so late...]
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.