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...]
Related
I'm a beginner programmer to C and I'm trying to write a basic shell. I'm trying to use the fork() function, but it simply doesn't seem to work. I get caught in an endless loop of just my shell's prompt taking input and then seemingly doing nothing with it.
I ran the debugger and set the breakpoint to where the program forks, and at that point, I got an error message of
Can't find a source file at "/build/glibc-Cl5G7W/glibc-2.23/posix/../sysdeps/nptl/fork.c"
Locate the file or edit the source lookup path to include its location.
What I think is happening is that I either messed up with my #include headers or that when I tried to compile, I left some library out. I've just been compiling with the standard
gcc -o shell custom_shell.c
and I recall my teacher saying something about compiling with libraries, but I thought my #include headers would cover that and I can't find anything else on the topic online.
The parts of my code I'm wary over are
#include <stdlib.h>
#include <stdio.h>
#include <unistd.h>
#include <string.h>
#include <sys/types.h>
#include <sys/wait.h>
...
pid_t pid = fork();
if (pid < 0){ //error
perror("fork");
exit(1);
}
else if (pid == 0){ //child
execvp(args[0], args);
}
else{ //parent
wait(0);
}
Is it possible to generate a mini core dump for debugging purpose without crashing the process. Let's say if a function receives an unexpected value, just printing logs and returning gracefully might not be sufficient to debug the issue. On the other hand, if i can get a screenshot of memory and look at the stack, i could find more useful information to debug.
Yes,
According to gdb's documentation, once attached with gdb you may issue the following command:
(gdb) gcore
(gdb) q
This will dump the core to "core.pid" without crashing the process.
or this one-liner:
sudo sh -c 'echo gcore <output_core> | gdb -p <pid>'
There is not building function to do that, you could use ptrace() to debug your own process but it would not be easy. Call gcore is the easiest method.
#include <stdio.h>
#include <unistd.h>
#include <inttypes.h>
#include <sys/wait.h>
int main(void) {
pid_t parent = getpid();
pid_t pid = fork();
if (pid < 0) {
// oh dear we are on trouble
} else if (pid == 0) {
char tmp[42];
snprintf(tmp, sizeof tmp, "%" PRIdMAX, (intmax_t)parent);
execvp("gcore", (char *[]){"gcore", tmp, NULL});
} else {
int wstatus;
waitpid(pid, &wstatus, 0);
}
}
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 wrote the following code but I always get the output: "ERROR!" (the execv function not scheduled to return)
What am I doing wrong???
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <time.h>
#include <math.h>
#include <string.h>
#include <malloc.h>
#include "LineParser.h"
#define LOCATION_LEN 200
char* getL(void);
int main(int argc,char *argv[])
{
char *loc = getL();
char *args[] = {loc,"ls",NULL};
int i;
execv(args[0],args);
printf("ERROR!");
free(loc);
}
char* getL(void)
{
char *buff = (char**)malloc(sizeof(char)*LOCATION_LEN);
getcwd(buff,LOCATION_LEN);
return buff;
}
Read documentation of execv(3) and of execve(2) and of perror(3). At the very least, you should code
int main(int argc, char *argv[]) {
char *loc = getL();
char *args[] = { loc, "ls", NULL };
int i;
execv(args[0], args);
perror("execv");
free(loc);
}
You should compile with gcc -Wall -g then use the gdb debugger.
Your usage of execv is obviously wrong (you need a full path, e.g. "/bin/ls", and the order of arguments is wrong). You probably want exevcp(3) and you should in fact code at least:
char *args = { "ls", loc, NULL };
execvp("ls", args);
perror("execvp")
If you insist on using specifically execv(3) you could try
char *args = { "ls", loc, NULL };
execv("/bin/ls", args);
perror("execv")
I don't understand what your code is supposed to do. You might be interested by glob(7) & glob(3).
You probably should read Advanced Linux Programming. It seems that there are several concepts that you don't understand well enough. I guess that strace(1) could be useful to you (at least by running strace ls *.c to understand what is happening).
Maybe your getL is exactly what the GNU function get_current_dir_name(3) is doing, but then the (char**) cast inside it is grossly wrong. And you should better clear the buffer buff using memset(3) before calling getcwd(2) (and you should test against failure of ̀ mallocand ofgetcwd`)
Perhaps you want opendir(3), readdir(3), asprintf(3), stat(2); with all these, you could even avoid running ls
If you are coding some shell, you should strace some existing shell, and after having read all the references I am giving here, study the source code of free software shells like sash and GNU bash
You are not passing the correct arguments to execv. The first argument must be a path to the executable you wish to run but you are passing the path to the current working directory.
Update getL to return the full path to ls.
I was working on my project when I needed to use "curl" to obtain some data from www. Now firstly I tried direct system() function but it didn't worked, strangely everytime it corrupted the whole source code file while compiling with gcc. Luckily I was testing it separately.
Then I tested execl() function, this code compiles OK and gcc gives me a .exe file to run, but nothing happens when I run it,blank windows appears. CODE:
int main(){
execl("curl","curl","http://livechat.rediff.com/sports/score/score.txt",">blahblah.txt",NULL);
getch();
return 0;
}
Includes are not shown properly but I have included stdio,conio,stdlib and unistd.h.
How can I get output of program to store in text file? Also running the above command creates and stores text file in My Documents, I want it to be in local directory from where I run the program. How can I do that?
You need to provide the path of curl, and you cannot use redirection because the application will not be executed through bash. Instead use the -o flag and specify the filename. Also, execl does not return when successful:
#include <unistd.h>
#include <stdio.h>
int main(){
execl("/usr/bin/curl",
"curl","http://livechat.rediff.com/sports/score/score.txt",
"-oblahblah.txt",NULL
);
printf("error\n");
return 0;
}
If you want your code to return, you should fork a child process to run the command. This way you can check the return code.
#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <unistd.h>
#define CURL "/usr/bin/curl"
int main()
{
pid_t pid;
int status;
pid = fork();
if (pid == 0)
{
execl(CURL, CURL, arg1, NULL);
}
else if (pid < 0)
{
printf("Fork failed\n");
exit (1);
}
else
{
if (waitpid(pid, &status, 0) != pid)
status = -1;
}
return status;
}
arg1 is whatever argument you want to use with curl or if you aren't using any than you obviously can omit it.