This question already has answers here:
C - Executing Bash Commands with Execvp
(3 answers)
Closed 6 years ago.
#include <stdio.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <unistd.h>
#include <stdlib.h>
#include <string.h>
void main(){
char *cmd;
pid_t pid;
while (1) {
printf("$ ");
fgets(cmd,1000,stdin);
if (pid = fork() == -1) {
exit(1);
}
else if (pid == 0){
execvp(cmd,&cmd);
}
else{
int status;
wait(&status);
}
}
}
I am making a simple shell that executes commands but when I enter the command at the prompt I keep getting segmentation fault. This is the most simple version that only works for one-argument commands like "ls"
For your problem, in your code,
fgets(cmd,1000,stdin);
cmd is uninitialized. It does not point to a valid memory. Accessing invalid memory invokes undefined behavior.
You need to allocate memory to cmd before you ca use that. Alternatively, you can consider making cmd an array, like char cmd[1000] = {0}; to avoid the need to allocate memory yourself.
Then, execvp(cmd,&cmd); is not quite right, it's not what you think it is. Read the man page for a better understanding.
That said, for a hosted environment, void main() should at least be int main(void) to have standard conformance.
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);
}
}
This question already has answers here:
printf anomaly after "fork()"
(3 answers)
Closed 7 years ago.
I was writing a multi-process program using fork() and i bumped into a problem.
Below is a sample code reproducing the problem (without any sort of error checking):
#include <stdio.h>
#include <unistd.h>
#include <sys/types.h>
int main() {
printf("hello world");
fork();
}
This code prints 2 "hello world" statements (one from parent and the other from child). However this should not be the case since the printffunction call is prior to the fork() system call.
After testing, the problem appears to be solved by the following:
#include <stdio.h>
#include <unistd.h>
#include <sys/types.h>
int main() {
printf("hello world\n"); \\ addition of the new line character
// or by using fflush(stdout);
fork();
}
My guessing is that the printf buffer is being copied while its not flushed, so the child process is emptying its copy of this buffer before exiting. Hence the other printf shows.
Can anyone provide a better explanation of this issue? Or even better, correct me if i am wrong or missing something.
The file handle stdout (which is used by printf) is by default line buffered, which means output using printf will be flushed (and shown in the console) either when there's a newline or when the buffer is full.
As fork creates an exact duplicate of the parent process, both processes have the same contents in the (un-flushed) output buffer, and both will be flushed when the two processes exits.
So yes you're correct in your guessing.
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.
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...]