I have problem with process in c code with argv parameters - c

Gcc compiler messages:
passing argument 1 of ‘srand’ makes integer from pointer without a cast [-Wint-conversion]
too many arguments for format [-Wformat-extra-args]
My code:
#include<stdlib.h>
#include<unistd.h>
#include<stdio.h>
#include<sys/wait.h>
void main(int argc,int* argv[])
{
srand(argv[1]);
srand(argv[2]);
printf("I am orginal MY PID %d and MY PPID %d \n",getpid(),getppid());
int pid,x,s,x1;
pid=fork();
if (pid!=0)//parent
{
printf("I am parnet and My PID %d and My PPID %d /n",getpid(),getppid());
for(int i=0 ;i<3;i++){
s=rand();
x=s%5;
sleep(x);
printf("parent sleep\n",x);
}
printf("the parent terminated with PID %d and PPID %d \n",getpid(),getppid());
}
else{//child
printf("i'm a child with PID %d and PPID %d \n" ,getpid(),getppid());
for(int i=0 ; i<3;i++){
sleep(x1);
s=rand();
x1=s%5;
}
printf("child sleep \n",x1);
printf("the child terminated with PID %d and PPID %d \n",getpid(),getppid());
}
}

For starters the function main shall be declared like
int main(int argc, char * argv[])
instead of
void main(int argc,int* argv[])
In any case the expressions argv[1] and argv[2] have a pointer type. So these calls of the function srand
srand(argv[1]);
srand(argv[2]);
are invalid. The function is declared like
void srand(unsigned int seed);
That is it expects an integer instead of a pointer.
And in any case before using argv[1] and argv[2] you need to check the value of argc.
And calling the function twice sequentially does not make sense.
In these calls of printf
printf("parent sleep\n",x);
//...
printf("child sleep \n",x1);
you specified the redundant arguments x and x1 that do not have corresponding conversion specifiers in the format string.
Also you are using uninitialized variables as for example
sleep(x1);
The variable x1 was not initialized.

Related

Share number of child process to parent process. Exit() & Wait() or global variable

I have the task that the parent process needs to output exit code of the child process. This exit code is supposed to be the sum of the child process id, with an added variable k and modulo 100 of the whole. I have tried two approaches to save the exit-code from the child process:
exit(exit-code) in child process and saving in parent process with wait(). You should still this in the comments
saving exit-code in global variable and outputting exit-code after wait() in parent process
However, both did not work. Could you help me how I could achieve it? Thank you!
#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <unistd.h>
#include <string.h>
#include <time.h>
//globale Variable
int out;
int main()
{
//Nutzereingabe von k:
int k=0;
scanf("%d",&k);
//Erzeugen eines Kindprozesses:
if(fork()==0)
{
//Kindprozess liegt vor
int zaehler=1;
char ausgabe[256]={0};
while(zaehler<=k){
//printf("%d\t"
int pid=getpid();
int ppid=getppid();
sprintf(ausgabe, "%d %c %d %c %d\n", pid,' ', ppid,' ',zaehler);
write(STDOUT_FILENO, ausgabe, strlen(ausgabe));
sleep(1);
zaehler++;
}
//write(STDOUT_FILENO, (getpid()+k)%100, strlen((getpid()+k)/100));
//printf("%d\n", (getpid()+k)%100);
out=(getpid()+k)%100;
printf("%i", out);
exit((getpid()+k)%100);
}
else
{
//Elternprozess liegt vor
time_t curtime;
time(&curtime);
printf("Start: %s", ctime(&curtime));
}
//int exitcode=wait(NULL);
wait(NULL);
//exitcode to String casten:
char str[24];
sprintf(str, "Exit-Code: %i\n", out);
//Ausgabe und exitcode zu einem String zusammenfuegen: (vorher concat())
//char* s = concat("Exit-Code: ", str);
//strncat(*str,"Exit-Code: ",str);
//Ausgabe des Exitcodes:
write(STDOUT_FILENO, str, strlen(str));
time_t curtime;
time(&curtime);
printf("Ende: %s\n", ctime(&curtime));
return 0;
}
From man wait:
pid_t wait(int *status);
If status is not NULL, wait() and waitpid() store status information in the int to which it points.
WEXITSTATUS(status)
returns the exit status of the child. This consists of the least significant 8 bits of the status argument that the child specified in a call to exit(3) or _exit(2) ....
So use:
}
// warte fur unserer kind
int exitstatus;
wait(&exitstatus);
// caste exitcode to string casten
char str[24];
sprintf(str, "Exit-Code: %d\n", WEXITSTATUS(exitstatus));

Exec function in c is not running

This is not running on my Mac for some reasons that I can't figure out. the output I am getting is only from the main.c
the output is
Parent PID 4066
Child PID 4067
Process 4067 exited with status 5
I need the main.c to execute counter.c and pass the argument 5 which I will then have to use it inside the for a loop, but I can't get exec to run at all no matter what path I put.
//main.c
int main(int argc, char *argv[]) {
pid_t childOrZero = fork();
if (childOrZero < 0){
perror("Error happened while trying to fork\n");
exit(-1);
}
if (childOrZero == 0){
printf("Child PID %d\n", (int)getpid());
execl("./counter", "5", NULL);
exit(5);
}
// THis must be parent
printf("Parent PID %d\n", (int)getpid());
int status = 0;
pid_t childpid = wait(&status);
int childReturnedValue = WEXITSTATUS(status);
printf("Process %d exited with status %d\n", (int)childOrZero, childReturnedValue);
return 0;
}
counter.c
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
int main (int argc, char *argv[]){
for (int i = 0; i<5; i++){
printf("Process: %d %d\n", (int)getpid(),i);
//sleep(3);
}
}
In a comment, you mention you compile counter.c into an executable called a.out. This is the default executable name when you do not provide an output name explicitly to the compiler. Thus, if you compile both counter.c and main.c, only one of them will be the a.out.
You can provide gcc an option to name your executable different from the default:
gcc -o counter counter.c
Also, your invocation of execl is not quite correct. The first argument is the path to the executable, but the remaining arguments will become argv[0], argv[1], etc. Thus, you really want to invoke execl this way:
execl("./counter", "counter", "5", NULL);
Read documentation of execl for MacOSX and the POSIX specification of execl
It can fail (and that is the only case when it is returning). So code:
if (childOrZero == 0){
printf("Child PID %d\n", (int)getpid());
execl("./counter", "5", NULL);
perror("execl counter");
exit(5);
}

Fork() is not returning an id > 0 in the parent process

I am currently trying to learn about fork() and processes in general.
I have the task to perform fork() a certain amount of times - n - which the user can enter. Also, I am supposed to use waitpid() to wait for the termination of my process. Each process is supposed to return a random number beetween 1 and 6.
Here is my code so far:
#include <time.h>
#include <stdlib.h>
#include <stdio.h>
int main(){
int n,i;
int *returnvalue;
int pid;
int waitingID;
time_t t;
srand((unsigned)time(&t));
printf("How many processes to start?\n");
scanf("%d",&n);
for(i=0; i < n; i++){
pid = fork();
if(pid==0){
printf("I am %d, from iteration %d\n",getpid(), i);
}
else if(pid > 0){
waitingID = waitpid(pid, returnvalue, 0);
printf("Return-value of %d is: %d\n", waitingID, *returnvalue);
}
else{
printf("A problem occured.");
}
}
return rand()%6;
}
Here is an example output of the current program:
How many processes to start?
5
I am 6449, from iteration 0
I am 6450, from iteration 1
I am 6451, from iteration 2
I am 6452, from iteration 3
I am 6453, from iteration 4
Segmentation fault (core dumped)
As you can see, I have a few problems:
The else if (pid>0) is not being called at all. Therefore no waiting happens. Shouldn't this be called in each fork, for the corresponding parent process?
Also, as soon as the last iteration is over and it gets to the return, I get that Segmentation fault(core dumped) error.
I am lost right now. I can't quite figure out where my mistake is at.
int *returnvalue;
This is just a pointer to int, but pointing nowhere defined, so this:
waitingID = waitpid(pid, returnvalue, 0);
will write the status code to some random memory location that probably doesn't belong to your process (in terms of c, it is undefined behaviour to write through an uninitialized pointer).
Simple thing to do, instead of defining a pointer, define an actual int variable:
int returnvalue;
and pass a pointer to that variable:
waitingID = waitpid(pid, &returnvalue, 0);
You don't get any output for the parent case because the parent process waitpid is causing the segmentation fault. returnvalue is any uninitialised pointer. You need to do this:
int returnvalue;
...
pid = fork();
if(pid==0){
printf("I am %d, from iteration %d\n",getpid(), i);
}
else if(pid > 0){
waitingID = waitpid(pid, &returnvalue, 0);
printf("Return-value of %d is: %d\n", waitingID, returnvalue);
}
But even that isn't really what you want. The return value from waitpid should not be used as is. You need to use the WIF macros to determine the child exist status and then use WEXITSTATUS macro to get the return value. This is the example from the man page:
if (WIFEXITED(status)) {
printf("exited, status=%d\n", WEXITSTATUS(status));
} else if (WIFSIGNALED(status)) {
printf("killed by signal %d\n", WTERMSIG(status));
} else if (WIFSTOPPED(status)) {
printf("stopped by signal %d\n", WSTOPSIG(status));
} else if (WIFCONTINUED(status)) {
printf("continued\n");
}
The function waitpid tries to write to the storage pointed to by returnvalue. In your code returnvalue hasn't been initialized and thus
it's value is undefined.
Since waitpid is trying to write to an unknown address, it is causing a crash.
One way to mitigate this as suggested by others is to use int returnvalue and then pass its address as &returnvalue to waitpid.
This way since the variable returnvalue is created on stack, its address is welldefined and waitpid can write to it as well.
One other value that you can do is, although it is not very efficient is to call malloc and give your pointer a address(storage which will be created on the heap as opposed to the stack) so that you can then pass it to waitpid. But don't forget to call free on it afterwards.
returnvalue = malloc(sizeof(int));
waitingID = waitpid(pid, returnvalue, 0);
printf("Return-value of %d is: %d\n", waitingID, *returnvalue);
free(returnvalue);

Simple shell implementation with C in linux, fork causing infinite loop

I'm trying to implement a simple shell in C and my program is causing an infinite loop and creating a ton of new processes/printing Myshell> before the user has a chance to enter in any commands. I can't seem to find a way to prevent this and if anyone could help that would be great! (Didn't paste the #include headers at top
int main(int argc, char *argv[]){
char buffer[512];
int *status;
size_t nargs;
pid_t pid;
char delim[] = "\n";
while(1){
pid = fork();
if(pid){
printf("Myshell> ");
fgets(buffer, 512, stdin);
//parse(buffer, argv);
argv[0] = strtok(buffer, delim);
for(argc=1; argv[argc-1]; argc++){
argv[argc] = strtok(NULL, delim);
}
if(!strcmp(argv[0], "exit"))
exit(0);
printf("Waiting for child (%d)\n", pid);
pid = wait(status);
printf("Child (%d) finished\n", pid);
exit(0);
}else{
if(execvp(argv[0], argv)){
printf("error");
exit(1);
}else{
exit(0);
}
}
}
return 0;
}
Because you are reading command into buffer using fgets but not from command line argument So argv[argc] for argc > 1 is wrong - undefined behaviour.
When you don't pass any extra command line argument then argv[0] is your program name and argv[1] is NULL. indexing to argv[] for value more then 1 causes array out of index problem.
Instead of declare argv[] and argc as main function parameter declare within main as formal variable something like:
int argc;
char* argv[MAX]; // max number of argument can be pass to your shell
One more rectification in your code, change:
int *status;
as
int status;
and accordingly correct
pid = wait(status);
as
pid = wait(&status);

Reading commands from cmd line, and executing them in C

I'm writing a program to take user input from the command line (linux/unix commands), and execute them within my program.
My steps so far:
Ask user for number of commands input
Fork() to create child process
Output Child PID and Parent PID
Allow user to input each command, read each input into an index of argv
Use execv to run each command inside of argv
The main issue is that when it executes, it merely does the "bin/ls/" in the execv command.
Here is a sample output from running my program:
Enter number of commands: 2
Child's PID is 3487. Parent's PID is 3485
Enter a UNIX command: ls
Enter a UNIX command: -al
LIST OF FILES AS IF TYPING "LS" ON THE CMD LINE
Process Complete.
And here is my source code:
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <sys/types.h>
void main(int argc, char *argv[20])
{
int pid;
int num = 0;
printf("Enter number of commands: ");
scanf("%d", &argc);
pid = fork();
if(pid == 0)
{
printf("Child's PID is %d. Parent's PID is %d\n", (int)getpid(), (int)getppid());
for(num=0; num < argc; num++)
{
printf("Enter a UNIX command: ");
scanf("%s", argv[num]);
}
argv[num+1] = 0;
execv("bin/ls/", argv);
}
else
{
wait(pid);
printf("Process Complete.\n");
exit(0);
}
}
Firstly you are defining char* argv[20] in main which is not a good idea. If you ever pass in more than 20 arguments you will exceed the bounds of the array.
Secondly, you are attempting to read a string with scanf("%s", argv[num]) into an address space that is not initialized as far as I can tell.
The argv[] array of "strings" is initialized by the OS when your program is invoked and if you don't pass any arguments to your program you will not have any "strings", meaning that you will be writing to random memory which you might not own.
If you really want to load your commands the way you are doing it now please try the following:
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <sys/types.h>
void main(int argc, char *argv[])
{
int pid;
int num = 0;
int argc2 = 0;
char* argv2[20]; // argv2 will point inside of buffer for convenience.
char* buffer[2000]; // note each array has a limit of 100 characters.
printf("Enter number of commands: ");
scanf("%d", &argc2);
pid = fork();
if(pid == 0)
{
printf("Child's PID is %d. Parent's PID is %d\n", (int)getpid(), (int)getppid());
for(num=0; num < argc2 && num < 20; num++) // your array is 20 long
{
argv2[num] = &buffer[num * 100];
printf("Enter a UNIX command: ");
scanf("%s", argv2[num]);
}
argv[num] = 0; // no need to add + 1 because the for loop did already anyway.
execv("Assignments/ls", argv2);
}
else
{
wait(pid);
printf("Process Complete.\n");
exit(0);
}
}
Alternatively you could just pass arguments to your main program which simply passes them onto the called program like so:
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <sys/types.h>
void main(int argc, char *argv[])
{
int pid;
int num = 0;
printf("You entered %d commands: \n", argc);
for (num = 0; num < argc; ++num)
{
printf("\t%s\n", argv[num]);
}
pid = fork();
if(pid == 0)
{
printf("Child's PID is %d. Parent's PID is %d\n", (int)getpid(), (int)getppid());
execv("Assignments/ls", &argv[1]);
}
else
{
wait(pid);
printf("Process Complete.\n");
exit(0);
}
}
One specific problem your code has is you must pass argv[idx] as the argument to exec. You're passing an array of char pointers, by passing argv.
Please also be advised that argc contains the full count of arguments, and that full count includes the program itself. argv[0] contains the program name to which you are passing the arguments. I'm not seeing that being reflected in your for loop. That is you are processing your own program and running it.
The way I've written these is to traverse argv in a while (or for, if you prefer), using an int varaiable -- for example int idx=0; -- until I find an argv[idx] pointer that is null.
If, for example, you had three arguments, argc would be 4, and argv[3] would be your last argument to process. argv[4] would be null.
Based on some of the answers you've received, here's a discussion of execv and fork.
You have wrong logic. use fork just before execv
move execv (together with fork) out of the loop;
1st argument of the execv - is a path to the binary file to execute;
2nd - array of arguments to pass to the binary. Is this correct that you have in
the current directory the sub-directory named 'Assignments' and this
directory contains the executable named 'ls'? And, please, read 'man execv' carefully
Update:
Disregard points 1 and 2 above.
man execv:
The execv(), execvp(), and execvpe() functions provide an array of
pointers to null-terminated strings that represent the argument list
available to the new program. The first argument, by convention,
should point to the filename associated with the file being executed.
The array of pointers must be terminated by a NULL pointer.

Resources