creating unknown amount of process in child without pipe and semaphore - c

I am trying to make a modified shell.
I have tried several times, I searched a lot on the net, but I cannot fix my problem. first of all I do not want to run this code by pipe or semaphore.
I think with semaphore it would be even more difficult, because I do not now how many process should be there (maybe I am wrong, but it seems at least in this way).
In the first way, program makes the file correctly, but I cannot run a loop until the user enter "exit". I am trying with while(1) but it does not give me more than one file and the stdin is active only once.
in the second way, the user can use stdin until he inserts "exit", but again,
it does not give more than one file, moreover there is nothing inside.
I am trying to mix these two ways, I tried for more than one day, but I do not understand where is the problem. By the way, I think in the second way,
it should be the file descriptor.
also, please let me know that do I use the wait system call correctly or not?
Thank you in advance.
/first way/
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <dirent.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <string.h>
#include <fcntl.h>
//void MYshell(char *comm);
int main(){
/*
char cmd[100];
printf("<exit> closes shell\n");
printf("MYshell:$ ");
fscanf(stdin,"%s",cmd);
do{
if(strcmp(cmd,"exit")==0){
printf("shell has been closed.\n");
break;
exit(EXIT_SUCCESS);
}
MYshell(cmd);
printf("MYshell:$ ");
fscanf(stdin,"%s",cmd);
}while(1);
*/
//void MYshell(char *comm){
pid_t fork_ret;
int fd,dup_ret;
char cmd[100];
char name[100];
printf(" <exit> closes shell\n");
printf("MYshell:$ ");
fscanf(stdin,"%s",cmd);
if(strcmp(cmd,"exit")==0){
printf("shell has been closed.\n");
//break;
exit(EXIT_SUCCESS);
}
fork_ret = fork();
if(fork_ret == -1)
exit(1);
if(fork_ret == 0){
sprintf(name,"%d.log",getpid());
fd = open(name,O_CREAT | O_WRONLY,S_IRWXU|S_IRWXG|S_IRWXO);
if(fd<0){
printf("Error in opening or creating %s.\n",name);
exit(1);
}
dup_ret = dup2(fd,1);
if(dup_ret<0){
printf("Error in duplicating stdout descriptor.\n");
exit(1);
}
system(cmd);
close(fd);
exit(0);
}
//close(fd);
//exit(EXIT_SUCCESS);
if(fork_ret>0){
int stat;
pid_t child = wait(&stat);
printf("child = %d\n",child);
if(WIFEXITED(stat))
printf("ok\n");
else
printf("error\n");
}
wait(NULL);
exit(EXIT_SUCCESS);
}
/* second way*/
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <dirent.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <string.h>
#include <fcntl.h>
int fd;
char cmd[100];
void MYshell(void);
int main(){
pid_t fork_ret;
//int fd,dup_ret;
printf(" <exit> closes shell\n");
while(1){
printf("MYshell:$ ");
fscanf(stdin,"%s",cmd);
//tmp = fgets(cmd,sizeof(cmd),stdin);
if(strcmp(cmd,"exit")==0){
printf("shell has been closed.\n");
break;
exit(EXIT_SUCCESS);
}
}
fork_ret = fork();
if(fork_ret == -1)
exit(1);
if(fork_ret == 0){
MYshell();
exit(0);
}
if(fork_ret>0){
wait(NULL);
exit(0);
}
wait(NULL);
exit(EXIT_SUCCESS);
}
void MYshell(void){
char name[BUFSIZ];
int fd,dup_ret;
sprintf(name,"%d.log",getpid());
fd = open(name, O_CREAT|O_RDWR , S_IRWXU|S_IRWXG|S_IRWXO);
if(fd<0){
printf("Error in opening or creating %s.\n",name);
exit(1);
}
dup_ret = dup2(fd,1);
if(dup_ret<0){
printf("Error in duplicating stdout descriptor.\n");
exit(1);
}
system(cmd);
close(fd);
exit(0);
}

Related

Use read() to get the name of a file from a pipe and open() it in c

This is all done on a linux machine.
I have a pipe, fp, sending from the parent to the child the name of a file using a buffer.
The buffer is:
char buf[20];
the child has the following code:
{
//we are in the child
close(fp[1]);
int fd;
read(fp[0],buf,20);
if((fd=(open(buf, O_RDONLY)))==-1) exit(1);
else exit(0);
close(fp[0]);
}
Even if I type in the name of a file that exists, I'm getting the exit status of 1. So...
this unfortunately doesn't work. The issue is that the buff itself not only does '\n', but also also plenty of '\0', all of which don't actually exist in the name of real file. I've tried replacing the '\n' with a '\0' but that also doesn't work. How can I solve this?
Here's the whole code.
#include <stdlib.h>
#include <unistd.h>
#include <stdio.h>
#include <sys/syscall.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <fcntl.h>
int main(){
int fp[2];
if (pipe(fp) < 0){
printf("error creating pipe\n");
exit(-1);
}
int id;
char buf[20];
id=fork();
//father process here --------------------------------
if (id!=0){
close(fp[0]); //closing read
printf("program name: ");
fflush(stdout);
read(STDIN_FILENO,buf,20);
write(fp[1],buf,20);
int waitstatus, exitcode;
wait(&waitstatus);
//check if exited correctly
if (WIFEXITED(waitstatus))
exitcode = WEXITSTATUS(waitstatus);
else
{
printf("Bad exit\n");
return 0;
}
if (exitcode==1) printf("error, file doesn't exist\n");
else printf("file does exist\n");
close(fp[1]);
}
//child process here --------------------
else{
close(fp[1]); //closing write
int fd;
read(fp[0],buf,20);
//write(STDOUT_FILENO, buf, 20);
if((fd=(open(buf, O_RDONLY)))==-1) exit(1);
exit(0);
close(fp[0]);
}
}
You send the full buf which contains a newline and other indeterminate values. You need to remove the newline and I suggest that you only send what you need on the receiving end.
printf("program name: ");
fflush(stdout);
if(fgets(buf, sizeof buf, stdin)==NULL) return 1;
size_t len = strlen(buf);
buf[len - 1] = '\0'; // remove the newline
write(fp[1], buf, len); // only send what you actually need

C named pipe does not work with multiprocess

I would like to create a named pipe in the parent process and after write a string to it in the child process and finally read this string in the parent process. When run the program I dont get back the prompt like still waiting for end of child process. Why the child process not finished?
Current output:
Expected output:
(picture created without multiprocesses)
My source code:
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <sys/file.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <string.h>
#include <sys/wait.h>
int main() {
int pipefd[2];
pid_t cpid;
char szoveg[32];
int fd, ret;
char buf[32];
buf[0]=0;
cpid = fork();
if (cpid == -1) {
perror("fork");
exit(-1);
}
if (cpid == 0) {
printf("%d: Child process\n",getpid());
strcpy(buf,"Some text \0");
printf("%d:write to fifo: %s:%ld\n",getpid(),buf,strlen(buf));
write(fd,buf,strlen(buf));
exit(0);
} else {
printf("%d: Parent process\n",getpid());
ret=mkfifo("FifoName",00666);
if (ret == -1) {
perror("mkfifo()");
exit(-1);
}
fd=open("FifoName",O_RDWR);
if (fd == -1) {
perror("open() error!");
exit(-1);
}
wait(NULL);
ret=read(fd,buf,32);
printf("%d:read() Read %d bytes: %s\n",getpid(),ret,buf);
close(fd);
unlink("FifoName");
exit(0);
}
}
William Pursell right. The problem was the missing fd=open("FifoName",O_RDWR); line from child process.

How to get multiple strings from pointer that stores the output of a shell script in C?

I am trying to write a code in C with named pipes (fifo), where the client is asking for information about a directory.
The server checks for the existence of the directory, and sends back the size of the directory, and the number of files and subdirectories.
The request can also specify to get the name of the files and subdirectories.
The client gets the name of the directory as an argument, also the specification by -d option.
The server executes a shell script in order to solve the problem.
I already asked a question about this topic and got some improvements in the code, but still can't get it running correctly.
Here is the link to the question: How to pass multiple arguments to client (fifo)?
My problem is now that the server prints out only one file name instead of all filenames and subdirectories inside the directory that was given as an argument to the client.
Here is the modified server code:
#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <string.h>
#include <stdlib.h>
#include <unistd.h>
#include "header.h"
int f;
Message msg;
int main() {
if (mkfifo(FIFONAME, S_IFIFO | 0666) < 0) { /*Creating server fifo*/
perror("Failed creating own fifo");
printf("Server: Failed creating fifo_%d file\n", getpid());
unlink(FIFONAME);
exit(1);
}
if ((f = open(FIFONAME, O_RDONLY)) < 0) {
perror("Failed opening fifo");
unlink(FIFONAME);
exit(1);
}
printf("Server is working\n");
while (1) { /*Infinite loop, waiting for client requests*/
if ((read(f, &msg, sizeof(msg)))) {
if (strcmp(msg.dir, "exit") == 0) {
close(f);
unlink(FIFONAME);
exit(1);
}
switch (fork()) {
case -1: {
perror("Fork error\n");
exit(1);
}
case 0: {
char command[MAXLEN];
sprintf(command,"./shell.sh %s %s", msg.dir, msg.spec);
FILE *g;
if ((g = popen(command, "r")) == NULL) {
perror("Popen error");
exit(1);
}
fgets(msg.dir, MAXLEN, g);
fgets(msg.spec, MAXLEN, g);
char result[MAXLEN];
sprintf(result, "fifo_%d", msg.pid);
msg.pid = getpid();
int op;
op = open(result, O_WRONLY);
write(op, &msg, sizeof(msg));
close(op);
exit(0);
}
}
}
}
return 0;
}
And the client code:
#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <string.h>
#include <stdlib.h>
#include <unistd.h>
#include "header.h"
int f, fc;
Message msg;
char fifoname[MAXLEN];
int main(int argc, char *argv[]) {
if (argc == 1) {
printf("Usage: %s directory name\n",argv[0]);
exit(1);
}
sprintf(fifoname, "fifo_%d", getpid());
if (strcmp(argv[1], "0"))
if (mkfifo(fifoname, S_IFIFO | 0666) < 0) { /*Creating own FIFO file for result*/
perror("Failed creating own clientfifo");
printf("Client error: Failed creating fifo_%d file\n", getpid());
exit(2);
}
if ((f = open(FIFONAME, O_WRONLY)) < 0) { /*Opening serverfifo for writing*/
perror("Failed connecting to server");
exit(3);
}
strcpy(msg.dir, argv[1]);
strcpy(msg.spec, argv[2]);
msg.pid = getpid();
write(f, &msg, sizeof(msg));
if (strcmp(argv[1], "exit")) { /* The client is not expecting any result
because the server stopped*/
if ((fc = open(fifoname, O_RDONLY)) < 0) { /*Opening own fifo for reading*/
perror("Failed opening own fifo");
printf("Client error: Failed opening own %s file\n", fifoname);
exit(4);
}
read(fc, &msg, sizeof(msg));
printf("Client %d, received: %s%s\n", getpid(), msg.dir, msg.spec);
close(fc);
}
unlink(fifoname);
close(f);
exit(0);
}
The common header file:
#include <unistd.h>
#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <string.h>
#include <stdlib.h>
#define FIFONAME "server_fifo"
#define MAXLEN 1000
typedef struct {
int pid; /*folyamat azonositoja*/
char dir[MAXLEN];
char spec[MAXLEN];
} Message;
And the output I get is:
-bash-4.1$ ./client dir -d
Client 42723, received: 16K,2 directories, 2 files
a
While it should look like this :
-bash-4.1$ ./client dir -d
Client 42723, received: 16K,2 directories, 2 files
a
b
dir1
dir2
What needs to be modified in order to get the full output?
The problem is at line 52 inside server.c.
You are using fgets() to copy the output to msg.spec.
But fgets() stops taking input at newline charater ('\n').
Hence you only see one result.
To overcome this, you can do something like:
char str[100]; // arbitrary length
while(fgets(str, MAXLEN, g))
{
strcat(msg.spec, str);
}
This keeps taking input every iteration and concatenates each line to previous output.

synchronizing processes with alarms in c

I have to write a program about signals and alarms, and i can't use semaphores
A first process (named "B") launches another one (named "A"). "A" have to write random words in a file, once per 5 secs, if it writes the word END terminates the execution. The process "B" have to read the words from the file, if read END then relaunch the process "A". When "B" reads 50 words kills "A" and terminates the execution
The program does not work properly,I think it's because both processes accessing the file at the same time, but I do not know for sure
#include <stdio.h>
#include <stdlib.h>
#include <signal.h>
#include <sys/types.h>
#include <unistd.h>
#include <string.h>
#define SECS 5
#define MAX_READ 50
#define MAX_TAM 10
#define N_WORDS 13
int main(void){
int i=0,flag;
pid_t pid;
static char words[][MAX_TAM]={"THE","PROCESS","A","WRITES","IN","A","FILE","WORDS","AND","KILL","ITSELF","WITH","END"};
char *word;
char read[MAX_TAM];
FILE *fp=fopen("file2.txt","w");
if(!fp){
perror("Error opening file");
exit(EXIT_FAILURE);
}
if (signal(SIGALRM, SIG_IGN) == SIG_ERR){
puts("Error");
exit (EXIT_FAILURE);
}
while(1){
flag=0;
switch(pid=fork()){
case -1:
perror("fork error");
exit(EXIT_FAILURE);
case 0: /* A */
srand(getpid());
while(1){
if(alarm(SECS))
pause();
word = words[rand()%N_WORDS];
fprintf(fp,"%s ",word);
printf("A ~ WORD: %s\n",word);
fflush(stdout);
if(!strcmp(word,"END")){
fclose(fp);
printf("ENDING A\n");
exit(EXIT_SUCCESS);
}
}
default: /* Proceso B */
sleep(1);
for( ;i<MAX_READ;i++){
if(alarm(SECS))
pause();
fscanf(fp,"%s",read);
printf("B ~ READING %s\n",read);
fflush(stdout);
if(!strcmp(read,"END")){
flag=1;
break;
}
}
}
if(flag==0)
break;
}
kill(pid,9);
exit(EXIT_SUCCESS);
}

Using pipe between diffrent programs how ?

Question asked again and code modified...
I need to create three programs named as program0 program1 and program2 in linux.
Program0:Creates a parent with two child processes and executes program 1 and program 2 with its childs waits them to finish and close.
Program1:Takes a file name from the user and writes text to the file.It finishes writing when CTNL+D pressed and creates a pipe.After that by using cat command it writes file to stdout and uses dup() to create pipe which has file in it.
Program2:It reads filename from the pipe with the help of dup() and then executes wc command.
So far I managed to create all programs and I have no compling errors.Program 0 executes both programs.Program1 is also working and sends file to the pipe but program2 cannot read it from the pipe is prints weird symbols..
When I try to read from the pipe within the program1 it works(see the deactivated code in program1) but same code is not working if I put it inside program2.
So what how can I make program2 to read from the pipe after that I will try to execute wc command in program2 but first I should be able to see that its taking file input from the stdout so how?
I know its kinda long but please help me guys...
Program 0
#include <stdio.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <unistd.h>
#include <stdlib.h>
#define MAX 999
int main()
{
pid_t pid1, pid2;
pid1 = fork();
if(pid1<0)
{
fprintf(stderr,"Fork basarisiz");
exit(-1);
}
else if (pid1 ==0)/*child prosesleri*/
{
printf("program1\n");
execlp("./program1","program1",NULL);
execlp("./program2","program2",NULL);
}
else /*parent procsesleri */
{
wait(NULL);
pid2 = fork();
if(pid2<0)
{
fprintf(stderr,"Fork basarisiz");
exit(-1);
}
else if (pid2 ==0)/*child prosesleri*/
{
printf("\n");
printf("Program 2\n");
printf("\n");
execlp("./program2","program2",NULL);
//printf("\n");
}
else
{
}
/////////////////////////////////////////////////////////////////////////
wait(NULL);
printf("\n");
printf("Parent:Two child processes have successfully been created\n");
printf("Parent:Two child processes have successfully been terminated\n");
printf("Parent:This process will now terminate\n");
printf("\n");
exit(0);
}
}
Program 1
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/types.h>
#include <unistd.h>
#define MAX 999
int main()
{
char c[10000];
char file[10000];
int words;
printf("Child1:A text file will be created\n");
printf("Child1:Enter the name of the file\n");
scanf("%123s",file);
strcat(file,".txt");
FILE * pf;
pf = fopen(file, "w" );
if (!pf)
fprintf( stderr, "I couldn't open the file.\n" );
else
{
printf("Child1: Input a number of text lines ended, each ended by a CR (carriage return).\n");
/////////////////////////////
do
{
if (NULL != fgets(c, sizeof(c), stdin))
{
if (0 == strcmp(c, ".\n"))
{
break;
}
fprintf(pf, "%s", c);
}
else
{
if (0 != ferror(stdin))
{
fprintf(stderr, "An error occured while reading from stdin\n");
}
else
{
printf("Child1: Finish the input by CNTL^D\n");
}
break;
}
} while (1);
/////////////////////////////
}
printf("\nChild1:The file %s is succesfully created and saved in the current dictionary\n",file);
//////////////////////////////////////////////
/////////////////////////pipe///////////////
fclose(pf); // close file
char ch;
int outcount = 0;
int fd[2], nbytes;
pid_t childpid;
int i;
char f2[2];
char readbuffer[80];
pipe(fd);
if((childpid = fork()) == -1)
{
perror("fork");
exit(1);
}
if(childpid == 0)
{ printf("\nChild1:The file written to pipe with cat\n");
close(1) ;
dup(fd[1]);
close(fd[0]);
execlp("/bin/cat", "cat", file,NULL);
}
else
{
wait(NULL);
//close(0) ;
//dup(fd[0]) ;
//close(fd[1]);
//nbytes = read(fd[0], readbuffer, sizeof(readbuffer));
//printf("%s\n",readbuffer);
}
return(0);
}
Program 2
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/types.h>
#include <unistd.h>
int main()
{
int fd[2],nbytes;
pid_t childpid;
char readbuffer[80];
pipe(fd);
if((childpid = fork()) == -1)
{
perror("fork");
exit(1);
}
if(childpid == 0)
{
}
else
{
close(0) ;
dup(fd[0]) ;
close(fd[1]);
nbytes = read(fd[0], readbuffer, sizeof(readbuffer));
printf("%s\n",readbuffer);
}
return(0);
}
You may want to check the man pages for execve(2) (for starting cat) and dup2(2) (for overriding stdin and stdout as needed) for this one. execve will overwrite the currently executing program by a different one (same PID, same file descriptors), while dup2 will allow you re-define any of the standard file descriptors to point into any file descriptor you provide to it (such as any of the ends of your pipe).

Resources