how do i check if execv function faild or succeeded? - linux

i got an assignment to write a simple linux shell ,
this is the code so far :
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/wait.h>
#include <sys/types.h>
int main(int argc,char argv[])
{
char *token;
char command[50];
char tmp[256];
char *arg_command[]={"",0};
int pid,status,flag=0;
char *path = (char*)getenv("PATH");
while(1) // run always
{
printf("\n");
printf(getenv("PWD")); //print current dir
printf(": ");
gets(command);
if (strcmp(command,"exit")==0) //check for exit command
{
printf("bye\n");
break;
}
strcpy(tmp,path);
token = strtok(path,":");
while(token!=NULL)
{
arg_command[0] = command;
pid = fork();
if(pid>=0)
{
printf("\npid is:%d\n",pid);
if (pid==0) // child process is invoked
{
strcat(token,"/");
execv(strcat(token,command),arg_command);
exit(0);
}
else //parent process
{
wait(&status);
if(status==0)
}
}
else
{
printf("fork faild");
}
token = strtok(NULL,":");
}
if (flag == 1)
{
printf("no files or folders match this command\n");
}
strcpy(path,tmp);
}
return 0;
}
my question is how do i know whether execv was able to execute the command or not
because i want to output an error when ever the user entered a wrong command.
i also have a flag but because i cant check execv i cant use it .

Like most Unix/POSIX functions, exec* return an error code (-1) if they fail. errno will then tell you why it failed.
In fact, if they ever return, then something went wrong. Otherwise, the current process is replaced which means no code after is ever execute (exit(0) in your case).

Related

Why do I get the error message when reading from a FIFO?

On the Introduction to Operative Systems course we're asked to build a client-server model using FIFOs. As client we send a string to the server, the server gets this string and if a file with this name exists it sends back the first line on this file. If the file doesn't exist or it does exist but it happens to be empty, it sends an empty string back.
The problem is that in only works once, i send file1 for example, the server sends back the first line and when I send again file1 or another file's name in the same "session" the printf("First line of the file %s: \n%s\n", name, recived); doesn't happen, it enters into if (read(fifo_serv_client, recived, sizeof(recived)) == -1) { printf("An error occurred.\n"); }.
Any idea on why is this? I tried doing it two times with the same file, so it exists 100% but I still get the same result.
Thank you so much!
Here is the code for the client:
#include <stdio.h>
#include <fcntl.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <unistd.h>
#define BUFSIZE 512
int main()
{
int fifo_client_serv;
char *fifo1 = "fifo_client_serv";
int fifo_serv_client;
char *fifo2 = "fifo_serv_client";
char name[BUFSIZE];
while(1) {
printf("Write the file's name: ");
scanf("%s", name);
/* write str to the FIFO */
fifo_client_serv = open(fifo1, O_WRONLY);
fifo_serv_client = open(fifo2, O_RDONLY);
write(fifo_client_serv, name, sizeof(name));
char recived[BUFSIZE];
if (read(fifo_serv_client, recived, sizeof(recived)) == -1) {
printf("An error occurred.\n");
} else {
printf("First line of the file %s: \n%s\n", name, recived);
close(fifo_client_serv);
close(fifo_serv_client);
}
}
return 0;
}
And here's the code for the server:
#include <fcntl.h>
#include <stdio.h>
#include <sys/stat.h>
#include <unistd.h>
#include <string.h>
#include <errno.h>
#define BUFSIZE 512
int main()
{
int fifo_client_serv;
char *fifo1 = "fifo_client_serv";
int fifo_serv_client;
char *fifo2 = "fifo_serv_client";
char buf[BUFSIZE];
char line[BUFSIZE];
FILE *file;
/* create the FIFO (named pipe) */
mkfifo(fifo1, 0777);
mkfifo(fifo2, 0777);
printf("Server runnning...\n");
while (1)
{
fifo_client_serv = open(fifo1, O_RDONLY);
fifo_serv_client = open(fifo2, O_WRONLY);
read(fifo_client_serv, buf, BUFSIZE);
if((file = fopen(buf, "r")) == NULL) {
write(fifo_serv_client, "", BUFSIZE);
} else {
fgets(line, BUFSIZE, file);
write(fifo_serv_client, line, BUFSIZE);
}
/* clear buffer and line */
memset(buf, 0, sizeof(buf));
memset(line, 0, sizeof(buf));
close(fifo_client_serv);
close(fifo_serv_client);
unlink(fifo1);
unlink(fifo2);
}
return 0;
}
UPDATE I found why this happens, if I create the fifo inside the while it works fine! I just put mkfifo(fifo1, 0777); mkfifo(fifo2, 0777); first in the while. My question is, is it really necessary to create the FIFO each time I send a text from the client? Can't I just create once the FIFO, do the communication from it and close once I finish?
Can you try to close the file after read/writes in the server file ?
if((file = fopen(buf, "r")) == NULL) {
write(fifo_serv_client, "", BUFSIZE);
fclose(file);
} else {
fgets(line, BUFSIZE, file);
write(fifo_serv_client, line, BUFSIZE);
fclose(file);
}
By the way. Its worth to do error checking on your writes.

How does ptrace work with 2 different processes?

I was reading about ptrace on the net and found that a process can request to trace another process by using PTRACE_ATTACH but apparently all the examples available involve the use of fork().
What I want is to have 2 programs - prg1.c and prg2.c where prg2.c should trace prg1.c. I tried using PTRACE_ATTACH in prg2.c but it seems that the call failed - prg2.c couldn't trace prg1.c . How does ptrace work ? Can anybody explain ?
Code for prg1.c :
#include <stdio.h>
#include <sys/ptrace.h>
#include <unistd.h>
#include <stdlib.h>
int main()
{
printf("Hello world\n");
sleep(20);
execl("/bin/ls", "ls", NULL);
return 0;
}
Code for prg2.c :
#include <stdio.h>
#include <sys/ptrace.h>
#include <unistd.h>
#include <stdlib.h>
int main(int argc , char **argv)
{
int pid = atoi(argv[1]);
int status;
if (ptrace(PTRACE_ATTACH, pid, NULL, NULL) == -1) {
printf("ptrace attach failed!");
return 0;
}
wait(&status);
sleep(5);
ptrace(PTRACE_DETACH, pid, NULL, NULL);
return 0;
}
I have included a sleep() to get the pid of prg1's executable(during that time) using ps -af and give it as an input to the executable of prg2.

Linux Pipes and Redirecting output

I'm trying to write a linux program using pipes, but so far I've encountered a major problem.
When I try to run this, it seems it either duplicates the answers, or doesnt give me an answer at all.
So far I'm trying to use a pipe, the parent gets a string from the keyboard, and compares it to see if matches any other commands, momentarily its only the "login" command.
But it doesnt work as it doesnt show me a fail or success message. I've been fiddeling with the code, but sometimes it's repeating the answer several time, like it's executing the child several times. Can someone explain me why its happening?
Thx
#include <stdio.h>
#include <unistd.h>
#include <sys/types.h>
#include <errno.h>
#include <fcntl.h>
#include <string.h>
int fd[2], nbytes;
pid_t childpid;
char input[12];
char readbuffer[80];
int log_variable;
int pid;
int compare(char str1[], char str2[]){
if(strlen(str1) == strlen(str2))
{int i;
for( i=0; i<strlen(str1); i++){
if(str1[i] != str2[i])
return 0;
return 1;
}
}
}
int test(char argument[]){//test function
pipe(fd);
switch(childpid=fork()){
case -1:
perror("fork -1\n");
exit(1);
case 0://child
close (fd[1]);
int nbytes = read(fd[0], readbuffer, sizeof(readbuffer));
if(compare(readbuffer, "login") == 1){
return 1;
}
else if(compare(readbuffer, "login") == 0){
return 0;
}
exit(1);
default:
//parent
close(fd[0]);
write(fd[1], argument, sizeof(argument));
while(wait(NULL)!=-1);
}
}
main(){
while(1){
printf("Insert command: \n");
scanf("%s", input);
logs=(test(input));
if(logs == 1) {printf("success\n"); break;}
else if(logs == 0) {printf("fail\n"); continue;}
}
return 0;
}
a couple of problems for your code with a quick look:
compare function doesn't return value if length not equal.
test() function may get called twice in one process, which means fork more times.
the test() internally for the child will return to the main, also parent will return to main ... get things more complicated here (the child may fork a third time ...)
Use "strace -F" can give you a much better view what things happened behind.

Why the program didn't execute some sentences in this C programming or unix programming(execvp() System calls)?

I have the following program, when I run the program, I feel really confused that why my program didn't excute
int num=i;
printf("it is No.%d !",num);
printf("hello , I will excute execvp!");
My program basically create 6 child processes to excute executionbode() function, and then use execvp to overload original program. However, everytime when I run the program, the string "hello, I will execute execvp" never shows up! Also I think those three sentences above also didn't execute in the running program? can someone tell me why? Here is my program
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>
#include <unistd.h>
#include <sys/types.h>
#include "makeargv.h"
#include "redirection.h"
#include <sys/wait.h>
int executionnode(int i);
int main(){
pid_t childpid;
int i;
int row=6;
for(i=0;i<row;i++)
{ childpid=fork();
if(childpid==0)
continue;
else if (childpid>0)
executionnode(i);
else {
perror("something wrong");
exit(1);
}
}
}
int executionnode(int i){
sleep(i);
printf("hello, I am process:%ld\n",(long)getpid());
wait(NULL);
char *execArgs[] = { "echo", "Hello, World!", NULL };
int num=i;
printf("it is No.%d !",num);
printf("hello , I will excute execvp!");
execvp("echo", execArgs);
}
Can someone tell me why? and how to fix it? I feel it is really strange? Is it because of execvp() functions? I just began to learn operating system,so I am really confused about it! Thank you for helping me!
As user3629249 said you have some confusion. You'll get many children of children of children... and that wait(NULL) is useless :).
I used this structure to got your goal in my OS subject excercises.
#include <sys/types.h>
#include <unistd.h>
#include <stdio.h>
#include <errno.h>
#include <stdlib.h>
#define N 5
int main(int argc, char const *argv[])
{
pid_t pid,pids[N];
int i, num_pids = 0;
int state = 0;
int prior[]={1,3,5,2,4};
pid_t parent_pid = getpid();
printf("Parent pid is %i\n",father_pid);
// This for loop is the key
for (i = 0; i < N && getppid() != parent_pid; i++)
{
if ((pid = fork()) < 0)
{
printf ("fork error\n");
exit(-1);
}
pids[num_pids++] = pid;
}
if (pid == 0) // Child processes
{
printf("I am the child %i\n",getpid());
}
else // Parent process
{
for (i = 0; i < N; i++)
{
int pid_index = prior[i]-1; // Array starts with 0
pid = waitpid(pids[pid_index]);
printf("Children %i ended\n",pids[indice_pid]);
printf("%i alive children\n",N-1-i);
}
}
return 0;
}
This structure works because you save the parent's pid in parent_pid variable and compare the parent of each process pid with getppid(). If this pid is different that parent_pid, this proccess is the parent. In another case the process is a child so it has to stop (these processes don't have to fork). With this way you can get only the forks you need.
The rest of the code is the same: Pid==0 is child process and any other is the parent. You can call executionnode(int i) in child processes block (remember, pid==0 !!! you have a mistake). i variable should have the right value in each call I think.
Good luck!

OS-X Linux intercept process call

how do I intercept calls made from other process which I have called from my process. (say - I call make and I would like to intercept and modify call to gcc from make).
Here is a small example with ptrace:
#include <unistd.h>
#include <sys/ptrace.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <stdio.h>
#include <sys/user.h>
#include <sys/prctl.h>
const char *sys_call_name(long num);
int main()
{
pid_t pid = fork();
struct user_regs_struct regs;
if (!pid) {
/* child */
while (1) { printf("C\n"); sleep(1); }
}
else { /* parent */
int status = 0;
ptrace(PTRACE_ATTACH, pid, NULL, 0);
ptrace(PTRACE_SETOPTIONS, pid, NULL, PTRACE_SYSCALL) ;
while (1) {
printf("waiting\n");
pid = wait(&status);
/* child gone */
//if (WIFEXITED(status)) { break; }
ptrace(PTRACE_GETREGS, pid, 0, &regs);
/* regs.orig_eax is the system call number */
printf("A system call: %d : %s\n", regs.orig_eax, sys_call_name(regs.orig_eax));
/* let child continue */
ptrace(PTRACE_SYSCALL, pid, NULL, 0);
}
}
return 0;
}
const char *sys_call_name(long num) {
switch(num) {
case 4: return "write";
case 162: return "nanosleep";
case 165: return "getresuid";
case 174: return "rt_sigaction";
case 175: return "rt_sigprocmask";
default: return "unknown";
}
}
It sound from your question that you are looking for Makefile help, specifically you are looking for doing something for all call to the c-compiler.
make allows for any command to be redefined locally -- all you have to do is redefine the macro in make -- for gcc you would simply redefine the CC macros.
You could do that from the command like, like
make CC=echo
which would substitute all call from gcc to echo (not very useful, but you get the idea).
Or you can do it in the Makefile by adding a line like
CC=echo
testprogram: testprogram.o
and when you do make testprogram the make will echo something rather than invoking gcc
You don't easily. The facility in question is the ptrace function, not for the faint of heart.

Resources