I wrote a program that aims to simulate the terminal, more specifically, unnamed pipes. For example, I can simulate the terminal command cat file | grep 'aa'
using the command
./myterminal cat file - grep 'aa'
(I separate the arguments with - instead of |). And it works perfectly. However, if I try to use the command
./myterminal cat file - grep 'aa' - grep 'bb'
I get the error messege:
Usage: aa [OPTION] ... PATTERN [FILE]...
Try 'aa--help' for more information.
So obviously something is wrong. When I try the command
./myterminal cat file - grep 'aa' 'file' - grep 'bb' 'file'
The correct line from the file is printed -- however, so is the error message. What is happening here? Clearly something is wrong with my program, I just dont understand what. The program itself is so simple I'm not sure what's going wrong here.
The code itself is:
#include <stdio.h>
#include <dirent.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <assert.h>
#include <errno.h>
#include <string.h>
#include <stdlib.h>
#include <unistd.h>
void np_exec(char* cmd, char** argv)
{
int fd[2];
while(*(++argv) != NULL)
{
pipe(fd);
int pid = fork(); //parent executes
if(pid < 0)
{
printf("Error forking");
exit(1);
}
if(pid != 0) // parent
{
dup2(fd[1],1);
close(fd[0]);
if (execvp(cmd, argv) == -1)
{
perror("execvp failed");
}
}
else
{
dup2(fd[0],0);
close(fd[1]);
}
}
}
int main(int argc, char** argv)
{
assert(strcmp(argv[argc-1], "-"));
int i;
for (i = 1; i < argc; ++i) {
if (!strcmp(argv[i], "-"))
{
argv[i] = NULL;
np_exec(argv[1], &argv[1]);
argv = &argv[i];
argc -= i;
i = 0;
}
}
char* args[argc];
args[argc-1] = NULL;
for (i = 1; i < argc; ++i) {
args[i-1] = argv[i];
}
if (execvp(args[0], args) == -1)
perror("execvp failed");
return 0;
}
Does anyone know where I'm wrong?
Related
I'm trying to program a simple shell in C that can execute an executable by just entering the filename. I've tried writing my code which you will see below, but i keep getting the "NO such file or directory error. I'm new to C and I would really love someone to help.
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/wait.h>
/**
* main - a super simple shell
*
* Return: always 0
*/
int main(void)
{
char *command[] = {"", NULL};
size_t len = 0;
int flag = 1;
pid_t child_process;
int status;
while (flag == 1)
{
printf("#fountain-shell$ ");
getline(&command[0], &len, stdin);
child_process = fork();
if (child_process == -1)
{
perror("Error:");
return (1);
}
if (child_process == 0)
{
if (execve(command[0], command, NULL) == -1)
{
perror("Error:");
}
}
else
{
wait(&status);
continue;
}
}
}
This is an example of what I'm trying to achieve.
#cisfun$ /bin/ls
env-environ.c exec fork mypid ppid printenv promptc shell wait
env-main.c exec.c fork.c pid.c ppid.c prompt prompt.c shell.c wait.c
#cisfun$ ./ppid
5451
#cisfun$ ./ppid
5451
#cisfun$ ^C
Hey I have to write a small process launcher for uni.
#include <stdio.h>
#include <sys/types.h>
#include <unistd.h>
int main(int argc, char* argv[]){
pid_t pid;
if((pid = fork()) < 0){
return 0;
}
else if(pid == 0){
if(execvp(*argv, argv) < 0){
return 0;
}
}
return 0;
}
This is my program. I want to call it like ./process-launcher firefox --browser to start a new firefox process.
I think when I start the programm like this there should be a process of firefox in my system monitoring but it isn't
How do I get this?
Compiling with:
clang -o process-launcher process-launcher.c
What is in *argv? Your launcher name...
So when executing your code as is, you only relaunch your launcher...
Solution: ++argv;, it will pass the second parameter to execvp:
#include <stdio.h>
#include <sys/types.h>
#include <unistd.h>
int main(int argc, char* argv[]){
pid_t pid;
if((pid = fork()) < 0){
return 0;
}
else if(pid == 0){
++argv;
printf("execvp(%s, ...)\n", *argv);
if(execvp(*argv, argv) < 0){
return 0;
}
}
return 0;
}
I'm trying to make a program that simlutates the terminal's nameless pipes. For example, if I want to run the command:
ls –l | grep ‘10’
would be:
./pipes ls -l - grep '10'
(I use - instead of |).
However, my program doesn't work because execvp fails (bad adress). This seems impossible to me. What am I doing wrong? Any help would be welcome!
#include <stdio.h>
#include <dirent.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <assert.h>
#include <errno.h>
#include <string.h>
#include <stdlib.h>
void np_exec(char* cmd, char** argv)
{
int fd[2];
while(*(++argv) != NULL)
{
pipe(fd);
int pid = fork(); //parent executes
if(pid < 0)
{
printf("Error forking");
exit(1);
}
if(pid != 0) // parent
{
dup2(fd[1],1);
close(fd[0]);
if (execvp(cmd, *argv) == -1)
{
perror("execvp failed");
}
}
else
{
dup2(fd[0],0);
close(fd[1]);
}
}
}
int main(int argc, char** argv)
{
assert(strcmp(argv[argc-1], "-"));
int i;
for (i = 1; i < argc; ++i) {
if (!strcmp(argv[i], "-"))
{
argv[i] = NULL;
np_exec(argv[1], &argv[1]);
argv = &argv[i];
argc -= i;
i = 0;
}
}
char* args[argc];
args[argc-1] = NULL;
for (i = 1; i < argc; ++i) {
args[i-1] = argv[i];
}
if (execvp(args[0], args) == -1)
perror("execvp failed");
return;
}
Replace:
if (execvp(cmd, *argv) == -1)
by:
if (execvp(cmd, argv) == -1)
Notes:
a) is the warnign level you use high enough?
b) you must add a "#include" for "execvp". In this way, the compiler will find by itself this error.
c) last return statement must be "return 0". Again, compiler must warning you of this subject.
I need to implement nameless pipes using fork for my OS class but I cant get it to work. Its a simple code and have nothing special in it but I just dont get anything. Im trying to run
ls -l | wc -l but I get 0 everytime.
#include <stdio.h>
#include <dirent.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <fcntl.h> // for open flags
#include <time.h> // for time measurement
#include <assert.h>
#include <errno.h>
#include <string.h>
int pid,status;
int pipefd[2];
void my_exec(char* cmd, char** argv)
{
pipe(pipefd); // Fixed
pid = fork();
// pipe(pipefd); // Original
if(pid==0){
close(pipefd[0]);
dup2(pipefd[1],fileno(stdout));
close(pipefd[1]);
execvp(cmd, argv);
}
else {
close(pipefd[1]);
dup2(pipefd[0],fileno(stdin));
while(wait(&status)!=-1);
close(pipefd[0]);
return;
}
}
int main(int argc, char** argv)
{
assert(strcmp(argv[argc-1], "-"));
int i;
for (i = 1; i < argc; ++i) {
if (!strcmp(argv[i], "-")) {
argv[i] = NULL;
my_exec(argv[1], &argv[1]);
argv = &argv[i];
argc -= i;
i = 0;
}
}
char* args[argc];
args[argc-1] = NULL;
for (i = 1; i < argc; ++i) {
args[i-1] = argv[i];
}
if (execvp(args[0], args) == -1)
perror("execvp failed");
return;
}
btw the input for the command Im trying is ls -l - wc -l (instead of | type -)
OK Duck solved it: i should create the pipe before the fork, updated.
Your biggest problem is that you have the fork in front of the pipe. This will effectively have each branch of the fork call pipe() and thus you'll end up with two different pipefd sets, not the same set. Reverse the calling order of the fork() and pipe() and then you're file descriptors in each fork will be the same.
As a side note, you can do a printf() for debugging inside each of the if() statement components to make sure you're never seeing more than two descriptor numbers total.
I'm trying to create a c program that takes an executable and its arguments and runs them using execve, and then does some other stuff that shouldn't matter. The problem I'm having is that execve won't work when calling it on an exectuable assembly file. I think the problem is with my path because I can get the unix shell commands to work, but I can't get executables in the current directory (using ./spy ./executableName where spy is the name of my c program) to run. Here's the code:
#include <stdio.h>
#include <stdlib.h>
#include <sys/user.h>
#include <sys/reg.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <sys/ptrace.h>
#include <sys/types.h>
#include <unistd.h>
#include <string.h>
extern char **environ;
int main(int argc, char* const argv[]) {
pid_t pid;
char filename[50];
char* arglist[argc];
int i = 1,count = 0;
int status;
strcpy(filename, "/bin/");
strcat(filename,argv[1]);
for(i = 1; i< argc; i++)
arglist[i-1] = argv[i];
arglist[argc-1] = 0;
arglist[0] = filename;
if (argc == 1) {
fprintf(stderr,"usage : %s <prog> ...\n",argv[0]);
return -1;
}
pid = fork();
if(pid == 0) {
ptrace(PTRACE_TRACEME, 0, NULL, NULL);
if(execve(filename, arglist, 0) < 0)
fprintf(stdout,"Invalid file.");
}
else {
while(1) {
waitpid(pid,&status,0);
if (WIFEXITED(status))
break;
ptrace(PTRACE_SINGLESTEP, pid,NULL, NULL);
count++;
}
}
return 0;
}
From the source you posted it looks as if you were always prefixing the name passed as parameter with /bin/. So if the file isn't in /bin/ it can not be found, nor run.
Just change these two lines:
strcpy(filename, "/bin/");
strcat(filename,argv[1]);
to be:
strcpy(filename,argv[1]);
Note that having applied this modification the program to be run needs to be specified with its full path.
So to run ls you need to do specfify /bin/ls as parameter to the program.
Some other comments:
So avoid buffer a overflow for long path/file names change:
char filename[50];
to be:
char filename[PATH_MAX];
To get more detailed information on why an execve() might have failed change:
if(execve(filename, arglist, 0) < 0)
fprintf(stdout,"Invalid file.");
to be:
if(execve(filename, arglist, (char*) 0) < 0)
perror("execve() failed");
To detect a possible failure of forking do change:
pid = fork();
to become:
if (-1 == (pid = fork())) then
{
perror("fork() failed");
}
else