Using fgets() with pipe - c

I need to write program, which work on Linux OS:
when the main program starts, a child program separates from main program and child can be executed when it gets an interruption from parent program;
parent program waits for a text line, enetered from keyboard (text line should end by pressing );
after the text line is entered, parent program sends an interruption to child program, which reads the text line trough "Pipe" channel and creates a text file with it.
if an empty line is entered, then both parts of the program end their work.
The problem is, I know that it is bad to use gets(), so how can I use fgets() instead in my case?
#include <stdio.h>
#include <stdlib.h>
#include <errno.h>
#include <sys/types.h>
#include <unistd.h>
FILE *f;
int main(void)
{
int pfds[2];
char buf[1000];
pipe(pfds);
f = fopen("input.txt", "w");
fclose(f);
do
{
if (!fork())
{
printf("PARENT: enter input text from keyboard\n");
gets(buf);
printf("PARENT: writing to the pipe\n");
write(pfds[1], buf, 1000);
printf("PARENT: exiting\n");
exit(0);
}
else
{
f = fopen("input.txt", "a+");
printf("CHILD: waiting from PARENT\n");
read(pfds[0], buf, 1000);
printf("CHILD: read \"%s\"\n", buf);
fprintf(f,"%s\n", buf);
fclose(f);
printf("CHILD: input.txt file created\n", buf);
wait(NULL);
}
}
while (buf[0] != '\0');
printf("PROGRAM: done\n");
return 0;
}

You have opened file in "w" mode.
f = fopen("program.txt", "w");
w mode creates an empty file for writing. If a file with the same name already exists, its content is erased and the file is considered as a new empty file.
Open the file in "w+" or "a+" mode.

Related

getline() failing to retrieve input from stdin after resetting file descriptor with dup2()

Working on the implementation of a shell program, and I've run into an issue with one of functions. Scaled down, it's regarding standard input redirection with built in functions. In particular, I'm implementing a built in function to "pause" the system until the user hits enter. Since this is taking input from stdin, it should be able to work if I have previously redirected stdin using dup2() to another file. I have been able to redirect stdin and read from the input file without a problem, but the problem that I am getting is after I "clean up" and reset stdin back to its initial state, which I saved with dup().
The problem isn't that dup2() to reset is failing because I have other functions in my larger program implementation that reset both stdin and stdout in the exact same manner, and are able to retrieve input from getline() following this.
Below is the issue that I'm having boiled down to a small segment.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <fcntl.h>
int main(int argc, char ** argv){
char *input = NULL;
size_t len = 0;
int init;
int fd;
getline(&input, &len, stdin);
input = strtok(input, "\n");
if((fd = open(input, O_RDONLY)) == -1){
printf("error opening file\n");
}
if((init = dup(STDIN_FILENO)) == -1){
printf("error duping initial stdin\n");
}
if(dup2(fd, STDIN_FILENO) == -1){
printf("error duping fd\n");
}
close(fd);
while(getline(&input, &len, stdin) != -1){
printf("%s\n", input);
}
close(0);
if(dup2(init, STDIN_FILENO) == -1){
printf("error!\n");
}
getline(&input, &len, stdin);
printf("%s\n", input);
return 0;
}
This is the contents of the file the text file that I have been passing the program:
cd ..
echo 3207
touch test.txt
ls -la | grep test
cat < test.txt > out.txt
ls -l >> test.txt
It should be reading in input from the keyboard after printing these lines, but it simply prints the last line again and exits. Any advice is appreciated!

C program to convert to upper case using fork

I need to create a program that has a child process and a parent process. The child process has to convert lines sent by the parent proccess in to upper case, and the parent proccess has to send lines to the child proccess to convert, and show this converted lines by stdin. I already have this, but at the time when i execute on my terminal, the upper case lines doesn't show.
Any sugestion
#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <stdlib.h>
#include <sys/wait.h>
#include <string.h>
#include <ctype.h>
int main(void) {
int p1[2];
int p2[2];
pid_t pid;
char buffer[1024];
FILE *fp1;
FILE *fp2;
pipe(p1);
pipe(p2);
pid = fork();
if (pid < 0) {
fprintf(stderr, "Error fork\n");
exit(1);
}
if (pid == 0) {
// Close pipes entrances that aren't used
close(p1[1]);
close(p2[0]);
// Open file descriptors in used entrances
fp1 = fdopen(p1[0], "r");
fp2 = fdopen(p2[1], "w");
// Read from the corresponding file descriptor (pipe extreme)
while (fgets(buffer, 1024, fp1) != NULL) {
for (int i = 0; i < strlen(buffer); i++) {
buffer[i] = toupper(buffer[i]);
}
fputs(buffer, fp2);
}
// Once finished, close the reaming pipes entrances
fclose(fp1);
fclose(fp2);
exit(1);
}
// Close unused pipes entrances
close(p1[0]);
close(p2[1]);
// Open dile descriptors
fp1 = fdopen(p1[1], "w");
fp2 = fdopen(p2[0], "r");
while (fgets(buffer, 1024, stdin) != NULL) {
fputs(buffer, fp1); // Send buffer to write line pipe
fgets(buffer, 1024, fp2); // Get buffer readed from read line pipe
printf("%s", buffer); // Print in stdout the buffer
}
// Once finished, close the reaming pipes entrances
fclose(fp1);
fclose(fp2);
// Wait fork
wait(NULL);
return 0;
}
When using a FILE * stream and the C library stream API, it's important to keep in mind that I/O operations can be "buffered". In most cases, by default, when performing writes via fputs(...) the bytes will not actually be sent to the underlying file object (a pipe end in this case) until the buffer is flushed. In your code above, you could add calls to fflush(fpN) (where N matches the numbers in your code) after both calls to fputs(...). This should help fix your problem.
Note that alternatively there are ways of manually changing the buffering mode of a given file stream. This information can be found in man setbuf.

writing and reading within a fork - C

The exercise is simple. The father process lets me write my name and surname in a file. The son process waits 5 seconds, then reads and displays it. I can't use the #wait() function.
#include <cstdlib>
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <unistd.h>
int main(int argc, char** argv) {
char name[20];
char surname[20];
char outp[50];
// The file pointer
FILE *file;
// Open the file in write mode
file = fopen("dati.txt", "w+");
pid_t pid;
pid=fork();
if(pid>0){
printf("Father");
printf("Insert name: ");
scanf("%s",name);
for (int i=0; i<strlen(name); i++) {
if (i==0) {
if (name[i]>='a' && name[i]<='z')
name[i]-=32;
} else {
if (name[i]>='A' && name[i]<='Z')
name[i]+=32;
}
}
printf("Insert surname: ");
scanf("%s", surname);
for (int i=0; i<strlen(name); i++){
if (i==0){
if (surname[i]>='a' && surname[i]<='z')
surname[i]-=32;
} else {
if (surname[i]>='A' && surname[i]<='Z')
surname[i]+=32;
}
}
fputs(name, file);
fputs(" ",file);
fputs(surname, file);
printf("Father exits");
fclose(file);
exit(0);
}else{
sleep(5);
// position to the start of the file
rewind(file);
fgets(outp, 50, file);
printf("Read string: %s", outp);
fclose(file);
exit(0);
}
return 0;
}
If I insert name and surname before the 5th second, the program writes them, but doesn't display them. Otherwise, if I write the name and "accidentally" wait for the 5th second, it displays the file content (which are basically random characters).
You are closing the file in the main process, then you want to reuse the same pointer in the child process. This is not possible. You need to reopen the file in the child process.
So, you need to write this after the sleep() call:
file = fopen("dati.txt", "r");
You also won't need the #rewind() function call, as you will be back at the start of the file.
UPDATE: The problem was that w+ means
write/update: Create an empty file and open it for update
So, you the file was erased. With r mode, it works just fine.
PS: By the way, you shouldn't use cstdio in a C program, use only the standard stdio.h header file. There was also a compilation error, because you are redeclaring the loop variable i.
You need to fopen file after fork() both for parent and child separately:
if (pid > 0) {
/* Parent process */
file = fopen("dati.txt", "w+");
/* write to file */
...
} else {
/* child process */
sleep(5);
file = fopen("dati.txt", "r");
/* read from file */
...
}
With this change it will work. Mind that, only the parent process is actively connected to your console - the output of child will show after 5 seconds and might appear after parent process exits (due to no call to wait). So you can see "Father exists" message and get console prompt before child will show any output.

Can I write this code without using file stream

#include <sys/types.h>
#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
/* Read characters from the pipe and echo them to stdout. */
void read_from_pipe (int file)
{
FILE *stream;
int c;
stream = fdopen (file, "r");
while ((c = fgetc (stream)) != EOF)
putchar (c);
fclose (stream);
}
/* Write some random text to the pipe. */
void write_to_pipe (int file)
{
FILE *stream;
stream = fdopen (file, "w");
fprintf (stream, "Hello from Parent!\n");
fclose (stream);
}
int main (void)
{
int pid;
int mypipe[2];
/* Create the pipe. */
if (pipe (mypipe))
{
printf("Pipe failed.\n");
return EXIT_FAILURE;
}
/* Create the child process. */
pid = fork ();
if (pid == 0)
{
/* This is the child process.
Close other end first. */
close (mypipe[1]);
read_from_pipe (mypipe[0]);
return EXIT_SUCCESS;
}
else if (pid < 0)
{
/* The fork failed. */
printf ("Fork failed.\n");
return EXIT_FAILURE;
}
else
{
/* This is the parent process.
Close other end first. */
close (mypipe[0]);
write_to_pipe (mypipe[1]);
return EXIT_SUCCESS;
}
}
I want to write simple program to do this task:
Parent process creates a pipe using the pipe() system call.
Parent process creates a child process.
Parent process sends a message "Hello from Parent" to the child.
Child process prints the message to the screen.
This code creates File stream. I can't understand why. Without file stream can I do this thing..?
This answer may be helpful for a future Googler.
I guess this is what you are looking for.
Here is what I wrote:
#include <stdio.h>
#include <unistd.h>
int main(){
int p, f;
int rw_setup[2];
char message[20];
p = pipe(rw_setup);
if(p < 0){
printf("An error occured. Could not create the pipe.");
_exit(1);
}
f = fork();
if(f > 0){
write(rw_setup[1], "Hello from Parent", 18);
}
else if(f == 0){
read(rw_setup[0],message,18);
printf("%s %d\n", message, r_return);
}
else{
printf("Could not create the child process");
}
return 0;
}
To create child process we use fork(). fork() returns :
<0 fail to create child (new) process
=0 for child process
>0 i.e process ID of the child process to the parent process. When >0 parent process will execute.
pipe() is used for passing information from one process to another. pipe() is unidirectional therefore, for two-way communication between processes, two pipes can be set up, one for each direction.
You can read more details here.
You can also use File descriptors.
Basically, when you call pipe(), the operating system prepares two file descriptors and writes their "names" to the argument (mypipe in this case).
You can use these file descriptors without opening any file streams by using the standard operating system calls: write(), read(), close(), etc.

can't read from stream until child exits?

OK I have a program that creates two pipes -> forks -> the child's stdin and stdout are redirected to one end of each pipe -> the parent is connected to the other ends of the pipes and tries to read the stream associated with the child's output and print it to the screen (and I will also make it write to the input of the child eventually).
The problem is, when the parent tries to fgets the child's output stream, it just stalls and waits until the child dies to fgets and then print the output. If the child doesn't exit, it just waits forever. What is going on? I thought that maybe fgets would block until SOMETHING was in the stream, but not block all the way until the child gives up its file descriptors.
Here is the code:
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <sys/types.h>
#include <unistd.h>
int main(int argc, char *argv[]) {
FILE* fpin;
FILE* fpout;
int input_fd[2];
int output_fd[2];
pid_t pid;
int status;
char input[100];
char output[100];
char *args[] = {"/somepath/someprogram", NULL};
fgets(input, 100, stdin); // the user inputs the program name to exec
pipe(input_fd);
pipe(output_fd);
pid = fork();
if (pid == 0) {
close(input_fd[1]);
close(output_fd[0]);
dup2(input_fd[0], 0);
dup2(output_fd[1], 1);
input[strlen(input)-1] = '\0';
execvp(input, args);
}
else {
close(input_fd[0]);
close(output_fd[1]);
fpin = fdopen(input_fd[1], "w");
fpout = fdopen(output_fd[0], "r");
while(!feof(fpout)) {
fgets(output, 100, fpout);
printf("output: %s\n", output);
}
}
return 0;
}
The child should probably fflush() its output, and/or terminate lines properly. Otherwise the I/O buffering can hang on to the data for quite a while.
You can try to set the O_NONBLOCK flag (using fcntl()) on the child's output file descriptor before handing over control, but that will require you to change your parent code's accordingly. As pointed out in comments though, this won't help you overcome the buffering done at the C standard library level if the child uses FILE-based I/O.

Resources