This question already has answers here:
Pipe implementation
(2 answers)
C Minishell Adding Pipelines
(1 answer)
Closed 8 years ago.
I am building a simple shell in c using fork and execlp. I will be given a set of commands separated by pipes. eg: ls -l | wc -l .
I want to use pipes for intra process communication. So the output from ls -l is input for wc -l. There can any number of commands separated by pipes. I am not understanding whether to create a pipe between a child process and parent and then when I get a output from a child process somehow transfer that output to another child process... I have parsed the inputs. How can I go about this?
void excueteCommands() {
int i, j;
int fd[2];
int cid1;
commandNode* ptr = head;
while (ptr != NULL) {
for (i = 0; i <= pipeCount; i++) {
cid1 = fork();
if (!cid1) {
if (i != 0) {
dup2(fd[i - 1][0], 0);
}
if (i != pipeCount) {
dup2(fd[i][1], 1);
}
for (j = 0; j < pipeCount; j++) {
close(fd[j][0]);
close(fd[j][1]);
}
execlp(ptr->command, ptr->args, NULL);
exit(0);
}
ptr = ptr->next;
}
}
for (i = 0; i < pipeCount; i++) {
close(fd[i][0]);
close(fd[i][1]);
}
}
I also had same assignment last year. Your need not to handle input and output from one process to another separately. Just initialize pipes between the series of processes and the flow of input and output would take place itself. You only need to give input to first command and take output from the last command.
Following is code snippet I used.
#include <fcntl.h>
#include <errno.h>
#include <dirent.h>
#include <unistd.h>
#include <stddef.h>
#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <string.h>
#include <stdlib.h>
#include <pwd.h>
#include <grp.h>
#include <time.h>
#include <sys/wait.h>
int exit_flag = 0;
#define ARG_SIZE 100
int main ()
{
int size = 1000,i,j;
int pipe_count = 0;
int fd[100][2],cid1,cid2,length,status;
char string[][100] = {"ls","wc"};
pipe_count = 1;
if(pipe_count)
{
for(i = 0;i < pipe_count;i++)
{
pipe(fd[i]);
}
for(i = 0;i <= pipe_count;i++)
{
cid1 = fork();
if(!cid1)
{
if(i!=0)
{
dup2(fd[i-1][0],0);
}
if(i!=pipe_count)
{
dup2(fd[i][1],1);
}
for(j = 0;j < pipe_count;j++)
{
close(fd[j][0]);
close(fd[j][1]);
}
execlp(string[i], string[i], NULL);
exit(0);
}
}
for(i = 0;i < pipe_count;i++)
{
close(fd[i][0]);
close(fd[i][1]);
}
waitpid(cid1,&status,0);
}
else
{
execlp(string[0], string[0], NULL);
}
return 0;
}
In above code string[] array contains all commands separated by '|' in sequence. fd[][2] is array of file descriptors. fd[i][0] is input of i+1 command and fd[i][1] is output of ith command. So output of i goes to input of i+1 using fd[i] pipe.
I don't remember now how the dup2 and close commands were handled. May you may get them since you have done them recently. I there is any doubt then I would try my best to clarify.
Related
Very simple college code (Operational Systems class) to make the parent process read from string, then child process write the string, while using pipe.
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/wait.h>
int main(int argc, char* argv[])
{
int nDadosTx, nDadosRx;
int size = 2;
const char textoTX[] = "roger roger!";
char textoRX[sizeof(textoTX)];
int fd[size][2];
int i = 0;
while (i < size)
{
if (pipe(fd[i]) < 0)
{
puts("Erro ao abrir os pipes.\n");
exit(-1);
}
if (fork() == 0)
{
close(fd[i][0]);
nDadosTx = write(fd[i][1], textoTX, strlen(textoTX)+1);
if (nDadosTx != strlen(textoTX)+1)
{
printf("Tamanhos da mensagem incompativeis: %d, %d.\n", nDadosTx, strlen(textoTX)+1);
exit(1);
}
printf("%d dados escritos\n", nDadosTx);
printf("Droid %d a postos.\n------\n", i);
}
else
{
close(fd[i][1]);
nDadosRx = read(fd[i][0], textoRX, sizeof(textoRX));
printf("%d dados lidos: %s\n", nDadosRx, textoRX);
}
waitpid(-1, NULL, 0);
i++;
}
/*for (int i = 0; i < 6; i++)
{
close (fd[0]);
close (fd[1]);
}*/
return 0;
}
If the program executes just 1 time ok, but adding iteration:
2 iterations:
i = 0
normal print
i = 1
normal print
i = 1
normal print
(yes, again)
3 iterations:
i = 0
normal print
i = 1
normal print
i = 2
normal print
i = 2
normal print
i = 1
normal print
i = 2
normal print
i = 2
normal print
What's up?
gcc 10.1.0
"One issue is that the child processes are also running the code that only the parent should run - e.g the child processes also call waitpid and then fork on the next iteration. The child code path should exit or return prior to that. – #kaylum 5 mins ago "
#include <sys/types.h>
exit(EXIT_SUCCESS); in the end of the child did it.
My program as of now just executes other c program.But I want this process to take the (inputted value)% of CPU.As of now the new processes(forked processes) take only 0%of CPU..sometimes 0.1%.I want it to take the inputted% ex..25%
#include <ctype.h>
#include <unistd.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <signal.h>
printf("u_interval=%d\n", u_interval);
for (size_t i = 0; i < schedulees_count; ++i) {
schedulee_t *schedulee = schedulees[i];
printf("schedulee %zu: %d%%\n argv: [", i, schedulee->proportion);
for (size_t j = 0; schedulee->argv[j] != NULL; ++j) {
printf("\"%s\", ", schedulee->argv[j]);
}
printf("\b\b]\n");
int pid = fork(); //The parent(>0) and child(0) is formed
if (pid == 0) {
printf("Hello from Child!\n");
execv(schedulee->argv[0], schedulee->argv);
}
// parent process because return value non-zero.
else{
wait(NULL);
printf("Hello from Parent!\n");
schedulee->pid = pid;
kill(pid,SIGSTOP);
}
}
This is a part of the program where it executes the other programs(task) through the execv command.But the new process only takes 0.0%of CPU.I want it to have 25% of CPU usage for example.
I need to print the following sentence to the console "My name is Bond, James Bond" alternating the words using semaphores.
Whenever I print the words using line breaks "\n", everything prints in the expected order, however if I don't use line breaks everything prints out of order.
This is my code:
#include <stdio.h>
#include <stdlib.h>
#include <sys/mman.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <fcntl.h>
#include <wait.h>
#include <unistd.h>
#include <semaphore.h>
#include <string.h>
int main(){
pid_t pid;
int i = 0;
sem_t *sem[4];
char * names[4] = {"/sem_ex07_1", "/sem_ex07_2", "/sem_ex07_3", "/sem_ex07_4"};
for(i = 0; i < 4; i++){
sem_unlink(names[i]);
}
for(i = 0; i < 4; i++){
if((sem[i] = sem_open(names[i], O_CREAT | O_EXCL, 0644, 0)) == SEM_FAILED){
printf("sem_open() error\n");
sem_unlink(names[i]);
exit(1);
}
}
sem_post(sem[0]);
for(i = 0; i < 3; i++){
pid = fork();
if(pid == 0){
break;
}
}
if(pid == 0){
if(i == 0){
sem_wait(sem[0]);
printf("My");
sem_post(sem[1]);
sem_wait(sem[0]);
printf("Bond, ");
sem_post(sem[1]);
} else if(i == 1){
sem_wait(sem[1]);
printf("name ");
sem_post(sem[2]);
sem_wait(sem[1]);
printf("James ");
sem_post(sem[2]);
} else if(i == 2){
sem_wait(sem[2]);
printf("is ");
sem_post(sem[0]);
sem_wait(sem[2]);
printf("Bond.\n");
sem_post(sem[3]);
}
} else if(pid > 0){
sem_wait(sem[3]);
for(i = 0; i < 4; i++){
sem_unlink(names[i]);
}
}
return 0;
}
Why is my output only correct if I add a line break on each printf?
Why is my output only correct if I add a line break on each printf?
printf() is mostly by default line buffered. stdio functions which use streams (instead of file descriptors like write() does) use a buffer.
The buffer can be set via setvbuf(3).
See also Disable buffering for stdin and stdout using setvbuf()
my program should print out a prompt: myshell> when it is ready to accept input. It must read a line of input, accepting several possible commands. This is a very simple shell, so it only accepts two command: run and exit.
#include<stdio.h>
#include<string.h>
#include <sys/types.h>
#include <errno.h>
#include <stdio.h>
#include <sys/wait.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
int h=0;
void keep(int sig){
h=1;
}
int main()
{
signal(SIGINT,keep);//gets into the interrupt
while(1)
{
printf("myshell>");
char line[255];
fgets(line, 255, stdin);
if(!strcmp(line,"\n")){//checks if the given line is not empty
continue;
}
if(h)
{
h=0;
continue;
}
int g = 0;
char *words[5];
words[g] = strtok(line," \n");//Tokenize the given line
while (words[g]!=NULL)//splitting the tokens
{
g++;
words[g] = strtok(NULL," \n");
}
if(strcmp(words[0],"run")==0)
{
int status;
printf("myshell:Started child pid %d \n",getpid());
pid_t result = fork();
printf("myshell:Started child pid %d \n",getpid());
if(result>0)
{
wait(&status);//gets into the wait state
}
else if (result == 0)//new child process created
{
char *args[3];
int k=0;
while(k<4)//take the whole string into array and execute
{
args[k] = words[k+1];
k++;
}
int output;
output = execvp(*args,args);
if(output==-1)
{
printf("myshell: could not find the program %s\n",words[1]);
}
}
}
else if(strcmp(words[0],"exit")==0)//comparing with the exit
{
exit(1);
}
else
{
printf("myshell: %s is not a valid command\n",words[0]);
}
}
return 0;
}
it works good with
./myshell
myshell> run ls
myshell: started child pid 7973
myshell myshell.c
MY shell should support using ; to execute multiple programs with a single command. To make it simple, let's assume there is a space before and after the ;. For example:
./myshell
myshell> run ls -l ; date ; who
But this is not working with this code.
I have to create prog1 which take one argument with number of children have to create. (example "./prog1 5" - will create 5 children) Each of children will generate random number from 1 to 20. This number will be given to execl which will start prog2 (in same folder) which take as a argument this random number. Prog2 should sleep this random number time. After that it should return this random number to parent.
I created something like this but it still don't work properly.
prog1:
#include <stdio.h>
#include <sys/types.h>
#include <unistd.h>
#include <stdlib.h>
#include <sys/wait.h>
int main(int argc, char *argv[])
{
int n, i, pid;
int u = getppid();
int procesy = 0;
pid_t proc_id;
n = atoi(argv[1]);
for(i = 0; i < n; i++)
{
proc_id = fork();
if(proc_id==0)
{
srand(getpid());
u = 1 + rand()%20;
execl("./prog2", "prog2", u,0);
}
else
{
procesy++;
}
}
if(u == getppid())
{
for(i = 0; i < n; i++)
{
pid = wait(&u);
printf("Process %d ende\n", pid);
procesy--;
}
if(procesy == 0) printf("endc\n");
}
return 1;
}
prog2:
#include <stdio.h>
#include <sys/types.h>
#include <unistd.h>
#include <stdlib.h>
#include <sys/wait.h>
int main(int argc, char *argv[])
{
int n;
n = atoi(argv[1]);
sleep(n);
exit(n);
}
Change your loop to look something like the following, in order to properly call execl():
if(proc_id==0)
{
char arg[16];
srand(getpid());
sprintf(arg, "%d", 1 + rand()%20);
execl("./prog2", "prog2", arg, 0);
printf("I should not be here!\n");
exit(-1);
}
Then get rid of if(u == getppid()) (but keep the contents of the conditional). It seems with that if you were trying to filter out the child from running that block. When execl() works, the child is not going to run anything in this code after the execl()... the printf and exit I added will not be run. Those lines will only run if execl() fails, and in this simple case, the only way it will fail is if you've provided improper arguments.