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
Related
My homework is to execute a C program from Linux shell with N parameters: N file names.
I have to create N processes and for each process I have to create a .bak file with the file name specified in the parameters.
The professor suggests we use the cp command but I don't know how to proceed.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
#include <unistd.h>
#include <limits.h>
typedef char stringa[80];
typedef stringa strvett[DIM];
void usage(char* prog_name) {
fprintf(stderr,"Usage:\n\t%s: file1 file2 ... fileN dir_dest.\n", prog_name);
}
void main(int argc, char *argv[]) {
int i = 0, j = 0, status, N = argc - 2, n_children = N;
int[N] pid;
char[N]* files;
char[PATH_MAX - 1] wd;
char term = '0';
if (strcmp(argv[argc - 1], getcwd(wd, sizeof(wd)))) {
fprintf(stderr, "Invalid directory.\n");
usage(argv[0]);
exit(EXIT_FAILURE);
}
for (i = 0; i < N; i++) {
char[strlen(argv[i + 1])] files[i];
strcpy(files[i], argv[i + 1]);
}
for (j = 0; j < n_children; j++ ) {
pid[j] = fork();
if (pid[j] == 0) { // Executed by child
if (term == '1') exit(0);
else {
term = '1';
execl("/bin/ls", "ls", "-l", (char*)0);
// cp command???
}
}
else {
if (pid[j] > 0) printf("%d: child created with PID %d\n", getpid(), pid[j]); // Executed by parent
else {
perror("Fork error");
exit(1);
}
}
}
}
The below program forks child processes and each process create a .bak file, using cp command, with the same name as a file name specified in the argument list passed to program. Since, the last argument is dir_dest, I am assuming that it is the destination directory where the child processes are suppose to create .bak files. Follow the inline comments of program:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#define FL_EXTN ".bak"
#define PLEN 256
#define NLEN 64
void usage(const char* prog_name) {
printf("Usage:\n\t%s: file1 file2 ... fileN dir_dest.\n", prog_name);
}
int main(int argc, char *argv[]) {
char arg1[NLEN];
char dir_dest[PLEN];
// adding check for argc < 3, as it need minimum 2 arguments
// a file_name and dir_dest
if (argc < 3) {
usage(argv[0]);
exit(EXIT_FAILURE);
}
// add the command line argument validations
// for e.g. dir_dest is valid or not
strcpy (dir_dest, argv[argc - 1]);
// run loop for argc - 2 time as the first argument is process name and
// last is dir_dest, rest are files to be copy with .bak extension
for (int j = 0; j < argc - 2; j++) {
// leaving it up to you to add a check whether file argv[j+1]
// exits or not. Below code is based on assumption that files exist
strcpy (arg1, argv[j+1]);
// fork child process
pid_t child_pid = fork();
if (child_pid == 0) {
// in child process
char *cmdpath = "/bin/cp";
char *cmd = "cp";
char arg2[PLEN];
// prepare the .bak file absolute path using dir_dest
snprintf (arg2, PLEN, "%s/%s%s", dir_dest, arg1, FL_EXTN);
// replace child process with cp
execl(cmdpath, cmd, arg1, arg2, NULL);
// get here only if execl fails
perror("execl failed");
// exit child process
exit(1);
} else {
// in parent process
if (child_pid > 0) {
printf("%d: child created with PID %d\n", getpid(), child_pid);
} else {
perror("Fork error");
exit(1);
}
}
}
return 0;
}
Additional:
Using void as return type of main function is not as per standards. The return type of main function should be int.
I am trying to write a program that will fork, then open a file and execute it. The file it should execute is called child and it has been compiled. When I type ./child, it runs. However, when I run this program it does not execute the child program and I am prompted with the error message I put in "Execution failed". What I am doing wrong?
This is my parent class
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/wait.h>
int main (int argc, char **argv)
{
pid_t parent = getpid();
pid_t pid = fork();
if (pid == -1)
{
// error, failed to fork()
}
else if (pid > 0)
{
int status;
waitpid(pid, &status, 0);
}
else
{
int var = execvp("./child", NULL);
if(var < 0)
{
printf("Execution failed");
}
}
exit(0); // exec never returns
}
This is the child
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main (int argc, char **argv)
{
printf ("Im the child");
exit (0);
}
I actually don't know what you are doing wrong. After a copy and a compilation (and several warning complains) your code runs fine (GCC 7.2).
Obviously, child must be in the same working directory in which you run your main executable (the one that forks).
But probably I would write that code in this way, but I'm not an expert in forking:
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <sys/wait.h>
#include <errno.h>
extern int errno;
int main () {
pid_t pid = fork();
if (pid < 0) {
fprintf(stderr, "%s\n", strerror(errno));
return 1;
}
if (pid == 0) {
int ret = execl("./child", "", (char *)NULL);
if(ret < 0) {
fprintf(stderr, "%s\n", strerror(errno));
return 1;
}
} else {
wait(NULL);
}
return 0;
}
At least it tells you which error execl has encountered.
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?
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.