Process communication with semaphore in C - c

I'm writing two files:
a father.c with a parent process, and a son.c with a child process. They should use semaphore for synchronization. When I launch the father (compiled), the father process waits forever after the child process message:
Child ftok done.
father.c
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <errno.h>
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/sem.h>
typedef union _semun {
int val;
struct semid_ds *buf;
ushort *array;
} semun;
int initsem(key_t key){
int status = 0, semid;
semid = semget(key, 1, 0600 | IPC_CREAT | IPC_EXCL);
if(semid == -1){
if(errno == EEXIST){
semid = semget(key, 1, 0);
}
else{
semun arg;
arg.val = 1;
status = semctl(semid, 0, SETVAL, arg);
}
if(semid == -1 || status == -1){
perror("initsem failed\n");
return -1;
}
return (semid);
}
}
int waitSem(int semid) {
struct sembuf wait_buf;
wait_buf.sem_num = 0;
wait_buf.sem_op = -1;
if(semop(semid, &wait_buf, 1) == -1) {
perror("waitSem failed");
exit(1);
}
return(0);
}
int signalSem(int semid) {
struct sembuf signal_buf;
signal_buf.sem_num = 0;
signal_buf.sem_op = 1;
if(semop(semid, &signal_buf, 1) == -1) {
perror("signalSem failed");
exit(1);
}
return(0);
}
int main(){
pid_t pid;
key_t key;
int semid;
if(key = ftok("/home/user/Scrivania/test.txt", 'a') == -1){
perror("IPC error: ftok\n");
exit(1);
}
else{
printf("Ftok done\n");
}
semid = initsem(key);
pid = fork();
if(pid < 0){
printf("failed fork()\n");
}
else if(pid == 0){
printf("Child process with PID: %d\n", pid);
execl("/home/user/Desktop/son", "son", "",(char *)0);
}
else{
printf("Father process with PID: %d\n", pid);
printf("Waiting for my son\n");
waitSem(semid);
printf("My son has done\n");
signalSem(semid);
}
return 0;
}
son.c
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <errno.h>
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/sem.h>
typedef union _semun {
int val;
struct semid_ds *buf;
ushort *array;
} semun;
int initsem(key_t key){
int status = 0, semid;
semid = semget(key, 1, 0600 | IPC_EXCL);
if(semid == -1){
if(errno == EEXIST){
semid = semget(key, 1, 0);
}
else{
semun arg;
arg.val = 1;
status = semctl(semid, 0, SETVAL, arg);
}
if(semid == -1 || status == -1){
perror("initsem failed\n");
return -1;
}
return (semid);
}
}
int waitSem(int semid) {
struct sembuf wait_buf;
wait_buf.sem_num = 0;
wait_buf.sem_op = -1;
if(semop(semid, &wait_buf, 1) == -1) {
perror("waitSem failed");
exit(1);
}
return(0);
}
int signalSem(int semid) {
struct sembuf signal_buf;
signal_buf.sem_num = 0;
signal_buf.sem_op = 1;
if(semop(semid, &signal_buf, 1) == -1) {
perror("signalSem failed");
exit(1);
}
return(0);
}
int main(){
pid_t pid;
key_t key;
int semid;
if(key = ftok("/home/user/Desktop/test.txt", 'a') == -1){
perror("IPC error: ftok\n");
exit(1);
}
else{
printf("Ftok done\n");
}
semid = initsem(key);
waitSem(semid);
printf("Pre signal\n");
signalSem(semid);
printf("My operation\n");
return 0;
}

Related

Timer disarms when interval is too small

Timers seem to disarm after process is resumed (SIGCONT) ONLY when interval is too small.
I use timer_create with CLOCK_REALTIME.
My linux distribution is ubuntu 20.04.1
This is the code that shows the problem
#include <stdio.h>
#include <unistd.h>
#include <signal.h>
#include <errno.h>
#include <time.h>
#include <stdlib.h>
#include <memory.h>
volatile siginfo_t sigInfo;
void childFunction();
void parentFunction(pid_t pid);
void ignoreChild();
void signalFunction(int signo, siginfo_t* SI, void* data);
int main(int argc, char* argv[])
{
ignoreChild();
pid_t pid;
pid = fork();
switch(pid)
{
case -1:
{
perror("Error in fork!\n");
exit(EXIT_FAILURE);
}
case 0:
{
childFunction();
exit(EXIT_SUCCESS);
}
default:
{
parentFunction(pid);
break;
}
}
return 0;
}
void signalFunction(int signo, siginfo_t* SI, void* data)
{
sigInfo = *SI;
}
void parentFunction(pid_t pid)
{
struct sigaction sa;
struct timespec sleepTime = { .tv_sec = 1, .tv_nsec = 0};
sigemptyset(&sa.sa_mask);
sa.sa_flags = SA_SIGINFO;
sa.sa_sigaction = signalFunction;
if (sigaction(SIGCHLD, &sa, NULL) == -1)
{
perror("Error in sigaction!\n");
exit(EXIT_FAILURE);
}
//---- for blocking
sigset_t set = {0};
if (sigaddset(&set, SIGCHLD) == -1)
{
perror("Error in sigaddset!\n");
exit(EXIT_FAILURE);
}
while (1)
{
if (pause() == -1)
{
if (errno == EINTR)
{
if (sigprocmask(SIG_BLOCK, &set, NULL) == -1)
{
perror("Error in sigprocmask!\n");
exit(EXIT_FAILURE);
}
if (sigInfo.si_status == SIGSTOP)
{
printf("Child received SIG_STOP signal\n");
nanosleep(&sleepTime, NULL);
kill(pid, SIGCONT);
}
if (sigInfo.si_status == SIGCONT)
{
printf("Child received SIGCONT signal!\n");
}
if (sigInfo.si_code == CLD_EXITED)
{
printf("Child is dead!\n");
break;
}
if (sigprocmask(SIG_UNBLOCK, &set, NULL) == -1)
{
perror("Error in sigprocmask2!\n");
exit(EXIT_FAILURE);
}
}
}
}
}
void ignoreChild()
{
struct sigaction sa;
sigemptyset(&sa.sa_mask);
sa.sa_flags = SA_NOCLDWAIT;
if (sigaction(SIGCHLD, &sa, NULL) == -1)
{
perror("Error in sigaction!\n");
exit(EXIT_FAILURE);
}
}
void childFunction()
{
struct sigevent sev;
sev.sigev_notify = SIGEV_SIGNAL;
sev.sigev_signo = SIGSTOP;
struct timespec timeForTimer = { .tv_sec = 1, .tv_nsec = 0}; // set time for timer here!
struct itimerspec ts = { .it_interval = timeForTimer, .it_value = timeForTimer };
timer_t timer;
if (timer_create(CLOCK_REALTIME, &sev,&timer) == -1)
{
perror("Error in timer_create!\n");
exit(EXIT_FAILURE);
}
if (timer_settime(timer, 0, &ts, NULL) == -1)
{
perror("Error in timer_settime!\n");
exit(EXIT_FAILURE);
}
struct timespec timeToWaitInLoop = { .tv_sec = 0, .tv_nsec = 300000000};
for (int i=0; i<1000; ++i)
{
printf("I'm working!\n");
nanosleep(&timeToWaitInLoop,NULL);
}
}
When I set timeForTimer to 3 seconds the program works correctly, for 2 seconds it still works but for 1 second it doesn't.
To compile:
gcc -Wall main.c -lrt
This is shorter example
#include <stdio.h>
#include <signal.h>
#include <time.h>
#include <stdlib.h>
#include <memory.h>
#include <unistd.h>
int main(int argc, char* argv[])
{
struct sigevent sev;
sev.sigev_notify = SIGEV_SIGNAL;
sev.sigev_signo = SIGSTOP;
struct timespec timeForTimer = { .tv_sec = 1, .tv_nsec = 0}; // set time for timer here!
struct itimerspec ts = { .it_interval = timeForTimer, .it_value = timeForTimer };
timer_t timer;
if (timer_create(CLOCK_REALTIME, &sev,&timer) == -1)
{
perror("Error in timer_create!\n");
exit(EXIT_FAILURE);
}
if( timer_settime(timer, 0, &ts, NULL) == -1)
{
perror("Error in timer_settime!\n");
exit(EXIT_FAILURE);
}
struct timespec timeToWaitInLoop = { .tv_sec = 0, .tv_nsec = 300000000};
for (int i=0; i<1000; ++i)
{
printf("I'm working! (PID) %d\n", getpid());
nanosleep(&timeToWaitInLoop,NULL);
}
}
In above example only one SIGSTOP signal occured. After sending SIGCONT with command kill -18 <pid> there was no more SIGSTOP signals.It looks like my timer disarmed.

Semaphore values are not changing in Ubuntu

I'm trying to create a solution for the River Crossing Problem from "The Little Book of Semaphores" (Chapter 5, section 7, page 148), I'm using an Ubuntu virtual machine in my PC.
The problem is that the semaphores I created are not changing values, all of them stay at 0, I'm using four files.
What I do is, run buffer and then create two hacker processes and then two serf processes, the thing is that the "Boarding a X" message is printed before the boat is filled (at least four passengers) and when I print the semaphore values all of them are in 0.
header.h, where I declare Semaphore ids and operations:
#ifndef SEMAFOROS_H
#define SEMAFOROS_H
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/ipc.h>
#include <sys/sem.h>
#include <sys/shm.h>
#define BARRIER 10
#define MUTEX 11
#define SERFQUEUE 12
#define HACKERQUEUE 13
struct buffer {
int hackers;
int serfs;
};
int sem_wait(int semid, int sem_num, int val) {
struct sembuf op;
op.sem_num = sem_num;
op.sem_op = -val;
op.sem_flg = 0;
return semop(semid, &op, 1);
}
int sem_signal(int semid, int sem_num, int val) {
struct sembuf op;
op.sem_num = sem_num;
op.sem_op = val;
op.sem_flg = 0;
return semop(semid, &op, 1);
}
int mutex_wait(int semid, int sem_num) {
return sem_wait(semid, sem_num, 1);
}
int mutex_signal(int semid, int sem_num) {
return sem_signal(semid, sem_num, 1);
}
#endif
buffer.c, where I create the semaphores:
#include "header.h"
int main(int argc, char* argv[])
{
int semid, shmid, i;
key_t key;
if (argc != 1) {
printf("usage: %s\n", argv[0]);
return -1;
}
if ( (key = ftok("/dev/null", 65)) == (key_t) -1 ) {
perror(argv[0]);
return -1;
}
if ( (semid = semget(key, 4, 0666 | IPC_CREAT)) < 0 ) {
perror(argv[0]);
return -1;
}
semctl(semid, BARRIER, SETVAL, 4);
semctl(semid, MUTEX, SETVAL, 1);
semctl(semid, SERFQUEUE, SETVAL, 0);
semctl(semid, HACKERQUEUE, SETVAL, 0);
unsigned short final_values[4];
semctl(semid, 0, GETALL, final_values);
for (i = 0; i < 4; i++) {
printf("%3i", final_values[i]);
}
printf("\n");
if ( (shmid = shmget(key, sizeof(struct buffer), 0666 | IPC_CREAT)) < 0) {
semctl(semid, 0, IPC_RMID, 0);
perror("shmget");
return -1;
}
struct buffer *b = (struct buffer *) shmat(shmid, (void *) 0, 0);
b->hackers = 0;
b->serfs = 0;
shmdt(b);
return 0;
}
hackers.c, code for hackers:
#include "header.h"
#include <time.h>
void a_hacker(char* program) {
int semid, shmid, i, k, isCaptain = 0;
key_t key;
struct buffer *b;
if ( (key = ftok("/dev/null", 65)) == (key_t) -1 ) {
perror(program);
exit(-1);
}
if ( (semid = semget(key, 4, 0666)) < 0 ) {
perror(program);
exit(-1);
}
if ( (shmid = shmget(key, sizeof(struct buffer), 0666)) < 0 ) {
perror("shmid");
exit(-1);
}
b = (struct buffer *) shmat(shmid, (void *) 0, 0);
mutex_wait(semid, MUTEX);
b->hackers += 1;
if (b->hackers == 4) {
sem_signal(semid, HACKERQUEUE, 4);
b->hackers = 0;
isCaptain = 1;
} else if (b->hackers == 2 && b->serfs >= 2) {
sem_signal(semid, HACKERQUEUE, 2);
sem_signal(semid, SERFQUEUE, 2);
b->hackers = 0;
b->serfs -= 2;
isCaptain = 1;
} else {
mutex_signal(semid, MUTEX);
}
unsigned short final_values[4];
semctl(semid, 0, GETALL, final_values);
for (i = 0; i < 4; i++) {
printf("%3i", final_values[i]);
}
printf("\n");
sem_wait(semid, HACKERQUEUE, 1);
printf("Boarding a hacker\n");
semctl(semid, 0, GETALL, final_values);
for (i = 0; i < 4; i++) {
printf("%3i", final_values[i]);
}
printf("\n");
sem_wait(semid, BARRIER, 1);
if (isCaptain) {
printf("Fugaaaa\n");
mutex_signal(semid, MUTEX);
}
sem_signal(semid, BARRIER, 2);
shmdt(b);
exit(0);
}
int main(int argc, char* argv[]) {
int amount_hackers = 0, semid, i, pid;
key_t key;
if (argc != 2) {
printf("usage: %s amount_of_serfs amount_of_hackers\n", argv[0]);
return -1;
}
amount_hackers = atoi(argv[1]);
if (amount_hackers < 1) {
printf("%s: The amount_of_hackers must be a positive number greater than zero.\n", argv[0]);
return -1;
}
for (i = 0; i < amount_hackers; i++) {
if ( (pid = fork()) < 0 ) {
perror("fork");
return -1;
} else if (pid == 0) {
a_hacker(argv[0]);
} else {
}
}
return 0;
}
serfs.c, code for serfs:
#include "header.h"
#include <time.h>
void a_serf(char* program) {
int semid, shmid, i, k, isCaptain = 0;
key_t key;
struct buffer *b;
if ( (key = ftok("/dev/null", 65)) == (key_t) -1 ) {
perror(program);
exit(-1);
}
if ( (semid = semget(key, 4, 0666)) < 0 ) {
perror(program);
exit(-1);
}
if ( (shmid = shmget(key, sizeof(struct buffer), 0666)) < 0 ) {
perror("shmid");
exit(-1);
}
b = (struct buffer *) shmat(shmid, (void *) 0, 0);
mutex_wait(semid, MUTEX);
b->serfs += 1;
if (b->serfs == 4) {
sem_signal(semid, SERFQUEUE, 4);
b->serfs = 0;
isCaptain = 1;
} else if (b->hackers == 2 && b->serfs >= 2) {
sem_signal(semid, HACKERQUEUE, 2);
sem_signal(semid, SERFQUEUE, 2);
b->serfs = 0;
b->hackers -= 2;
isCaptain = 1;
} else {
mutex_signal(semid, MUTEX);
}
unsigned short final_values[4];
semctl(semid, 0, GETALL, final_values);
for (i = 0; i < 4; i++) {
printf("%3i", final_values[i]);
}
printf("\n");
sem_wait(semid, SERFQUEUE, 1);
printf("Boarding a serf\n");
semctl(semid, 0, GETALL, final_values);
for (i = 0; i < 4; i++) {
printf("%3i", final_values[i]);
}
printf("\n");
sem_wait(semid, BARRIER, 1);
if (isCaptain) {
printf("Fugaaaa\n");
mutex_signal(semid, MUTEX);
}
sem_signal(semid, BARRIER, 2);
shmdt(b);
exit(0);
}
int main(int argc, char* argv[]) {
int amount_serfs = 0, semid, i, pid;
key_t key;
if (argc != 2) {
printf("usage: %s amount_of_serfs amount_of_hackers\n", argv[0]);
return -1;
}
amount_serfs = atoi(argv[1]);
if (amount_serfs < 1) {
printf("%s: The amount_of_serfs must be a positive number greater than zero.\n", argv[0]);
return -1;
}
for (i = 0; i < amount_serfs; i++) {
if ( (pid = fork()) < 0 ) {
perror("fork");
return -1;
} else if (pid == 0) {
a_serf(argv[0]);
} else {
}
}
return 0;
}
Can someone please help me?

Close pipes get Bad file descriptor

Here is the code:
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <sys/stat.h>
#include <unistd.h>
#include <dirent.h>
int main(int argc, char **argv) {
int num = 2;
pid_t pid;
int i;
int p1[num][2], p2[num][2];
for (i = 0; i < num; i++) {
if (pipe(p1[i]) == -1) {
perror("pipe");
exit(1);
}
if (pipe(p2[i]) == -1) {
perror("pipe");
exit(1);
}
}
for (i = 0; i < num; i++) {
if ((pid = fork()) == 0) {
if (close(p1[i][1]) != 0) {
perror("close");
exit(1);
}
if (close(p2[i][0]) != 0) {
perror("close");
exit(1);
}
printf("%d\n", getpid());
exit(0);
} else if (pid > 0) {
if (close(p1[i][0]) != 0) {
perror("close");
exit(1);
}
if (close(p2[i][1]) != 0) {
perror("close");
exit(1);
}
continue;
} else {
perror("fork");
exit(1);
}
}
for (i = 0; i < num; i++) {
if (close(p1[i][0]) != 0) {
perror("close1"); // <----error
}
if (close(p1[i][1]) != 0) {
perror("close");
}
if (close(p2[i][0]) != 0) {
perror("close");
}
if (close(p2[i][1]) != 0) {
perror("close2"); // <----error
}
}
for (i = 0; i < num; i++) {
if (wait(NULL) == -1) {
perror("wait");
exit(1);
}
}
return 0;
}
When I run this, it gives me this output
close1: Bad file descriptor
close2: Bad file descriptor
close1: Bad file descriptor
close2: Bad file descriptor
8798
8799
What I'm trying to do is to create two 2D array of pipes and fork num times.
The creating and running are working well, but some pipes can't close.
It seems that p1[i][0] and p2[i][1] are never closer properly.
The reason you're getting the EBADFD is you're attempting to close the same file descriptor twice.
I added a print statement in this first snippet of code to show/track what file descriptor is being closed. If you compile and run this you'll see that the error message appears right after you try to close the descriptor for a second time.
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <sys/stat.h>
#include <unistd.h>
#include <dirent.h>
int main(int argc, char **argv) {
int num = 1;
pid_t pid;
int i;
int p1[num][2], p2[num][2];
for (i = 0; i < num; i++) {
if (pipe(p1[i]) == -1) {
perror("pipe");
exit(1);
}
if (pipe(p2[i]) == -1) {
perror("pipe");
exit(1);
}
}
for (i = 0; i < num; i++) {
if ((pid = fork()) == 0) {
printf("Child closing: Pipe1 %d End %d\n", i, 1);
if (close(p1[i][1]) != 0) {
perror("close");
exit(1);
}
printf("Child closing: Pipe2 %d End %d\n", i, 1);
if (close(p2[i][0]) != 0) {
perror("close");
exit(1);
}
printf("%d\n", getpid());
exit(0);
} else if (pid > 0) {
printf("Parent closing: Pipe1 %d End %d\n", i, 0);
if (close(p1[i][0]) != 0) {
perror("close");
exit(1);
}
printf("Parent closing: Pipe1 %d End %d\n", i, 1);
if (close(p2[i][1]) != 0) {
perror("close");
exit(1);
}
continue;
} else {
perror("fork");
exit(1);
}
}
for (i = 0; i < num; i++) {
printf("Closing: Pipe1: %d End: %d\n", i, 0);
if (close(p1[i][0]) != 0) {
perror("close1"); // <----error
}
printf("Closing: Pipe1: %d End: %d\n", i, 1);
if (close(p1[i][1]) != 0) {
perror("close");
}
printf("Closing: Pipe2: %d End: %d\n", i, 0);
if (close(p2[i][0]) != 0) {
perror("close");
}
printf("Closing: Pipe2: %d End: %d\n", i, 1);
if (close(p2[i][1]) != 0) {
perror("close2"); // <----error
}
}
for (i = 0; i < num; i++) {
if (wait(NULL) == -1) {
perror("wait");
exit(1);
}
}
return 0;
}
Check for the pid and close the ends that weren't closed inside your first loop. This code assumes you are reading and writing on a specific pipe depending on the child's/parent's need. You may need to adjust to however your use case dictates:
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <sys/stat.h>
#include <unistd.h>
#include <dirent.h>
int main(int argc, char **argv) {
int num = 1;
pid_t pid;
int i;
int p1[num][2], p2[num][2];
for (i = 0; i < num; i++) {
if (pipe(p1[i]) == -1) {
perror("pipe");
exit(1);
}
if (pipe(p2[i]) == -1) {
perror("pipe");
exit(1);
}
}
for (i = 0; i < num; i++) {
if ((pid = fork()) == 0) {
if (close(p1[i][1]) != 0) {
perror("close");
exit(1);
}
if (close(p2[i][0]) != 0) {
perror("close");
exit(1);
}
printf("%d\n", getpid());
exit(0);
} else if (pid > 0) {
if (close(p1[i][0]) != 0) {
perror("close");
exit(1);
}
if (close(p2[i][1]) != 0) {
perror("close");
exit(1);
}
continue;
} else {
perror("fork");
exit(1);
}
}
for (i = 0; i < num; i++) {
if (pid == 0) {
if (close(p1[i][0]) != 0) {
perror("close1");
}
if (close(p2[i][1]) != 0) {
perror("close");
}
} else {
if (close(p1[i][1]) != 0) {
perror("close");
}
if (close(p2[i][0]) != 0) {
perror("close2");
}
}
}
for (i = 0; i < num; i++) {
if (wait(NULL) == -1) {
perror("wait");
exit(1);
}
}
return 0;
}

why this linux pseudo terminal program doesn't work?

Master reads input from stdin and writes to pty-master, slave reads input from pty-slave and writes to stdout.
But this code/program seems doesn't work.
The Master writes to pty-master is OK, but the slave hungs when reads from pty-slave.
anyone can help me? thx in advance.
#include <assert.h>
#include <fcntl.h>
#include <errno.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/stat.h>
#include <unistd.h>
/*
* copy from apue
*/
int ptym_open(char *pts_name, int pts_namesz)
{
char *ptr;
int fdm, err;
if ((fdm = posix_openpt(O_RDWR)) < 0) {
assert(0);
return -1;
}
if (grantpt(fdm) < 0) {
assert(0);
return -1;
}
if (unlockpt(fdm) < 0) {
assert(0);
return -1;
}
if ((ptr = ptsname(fdm)) == NULL) {
assert(0);
return -1;
}
strncpy(pts_name, ptr, pts_namesz);
pts_name[pts_namesz - 1] = 0;
printf("pts_name:%s\n", pts_name);
return fdm;
}
int ptys_open(char *pts_name)
{
int fds;
if ((fds = open(pts_name, O_RDWR)) < 0) {
return -1;
}
return fds;
}
int pty_fork(int *ptrfdm, char *slave_name, int slave_namesz)
{
int fdm, fds;
pid_t pid;
char pts_name[1024];
if ((fdm = ptym_open(pts_name, sizeof(pts_name))) < 0) {
assert(0);
return -1;
}
if (slave_name != NULL) {
strncpy(slave_name, pts_name, slave_namesz);
slave_name[slave_namesz - 1] = 0;
}
if ((pid = fork()) < 0) {
assert(0);
return -1;
} else if (pid == 0) {
if (setsid() < 0) {
assert(0);
}
if ((fds = ptys_open(pts_name)) < 0) {
assert(0);
}
close(fdm);
if (dup2(fds, STDIN_FILENO) != STDIN_FILENO) {
assert(0);
}
//if (dup2(fds, STDOUT_FILENO) != STDOUT_FILENO) {
// assert(0);
//}
//if (dup2(fds, STDERR_FILENO) != STDERR_FILENO) {
// assert(0);
//}
if ((fds != STDIN_FILENO) && (fds != STDOUT_FILENO) && (fds != STDERR_FILENO)) {
close(fds);
}
return 0;
} else {
*ptrfdm = fdm;
return pid;
}
}
int loop(int ptym)
{
pid_t pid;
int nread;
#define BUFFSIZE 512
char buf[BUFFSIZE];
if ((pid = fork()) < 0) {
assert(0);
} else if (pid == 0) {
while (1) {
if ((nread = read(STDIN_FILENO, buf, BUFFSIZE)) < 0) {
int errr = errno;
printf("%s\n", strerror(errr));
assert(0);
} else if (nread = 0) {
break;
}
if (write(ptym, buf, nread) != nread) {
int errr = errno;
printf("%s\n", strerror(errr));
assert(0);
}
fsync(ptym);
}
exit(0); // child
}
while (1) {
if ((nread = read(ptym, buf, BUFFSIZE)) <= 0) {
printf("%d break read\n", getpid());
break;
}
if (write(STDOUT_FILENO, buf, nread) != nread) {
assert(0);
}
}
}
int main(void)
{
int fdm;
char slave_name[1024];
pid_t pid = pty_fork(&fdm, slave_name, sizeof(slave_name));
if (pid < 0) {
assert(0);
} else if (pid == 0) {
int nread;
char buf[1024];
while(1){
if ((nread = read(STDIN_FILENO, buf, 3)) < 0) {
break;
}
printf("buf:%s\n", buf);
}
} else {
printf("child:%d#%s\n", pid, slave_name);
loop(fdm);
}
return 0;
}
Besides opening the pseudo-terminal, you have to initialize it (something referred to as line discipline). I don't see any of that in your example. You could compare with luit, which does do this (look for instance at the openTty function in sys.c).
Further reading:
Notes 7: Terminal I/O
Writing a Kernel Line Discipline
What are the responsibilities of each Pseudo-Terminal (PTY) component (software, master side, slave side)?

popen2: reading works, writing doesn't

The following function executes a process, returns its PID and provides file descriptors for reading and writing:
pid_t popen2(const char **command, int *infp, int *outfp)
{
int p_stdin[2], p_stdout[2];
pid_t pid;
if (pipe(p_stdin) != 0 || pipe(p_stdout) != 0) {
return -1;
}
pid = fork();
if (pid < 0) {
return pid;
} else if (pid == 0) {
close(p_stdin[WRITE]);
dup2(p_stdin[READ], READ);
close(p_stdout[READ]);
dup2(p_stdout[WRITE], WRITE);
execvp(*command, command);
}
if (infp == NULL) {
close(p_stdin[WRITE]);
} else {
*infp = p_stdin[WRITE];
}
if (outfp == NULL) {
close(p_stdout[READ]);
} else {
*outfp = p_stdout[READ];
}
return pid;
}
I call the above function with
pid = popen2(..., &in, &out);
and read from the file descriptor out with
nBytes = read(out, line, sizeof(line));
and what I read makes perfect sense. It is the output normally displayed on the console. However, when I try to write a command to the program which it would normally receive via the console with
nBytes = write(in, cmd, strlen(cmd)+1);
nothing happens. The program shows no reaction whatsoever.
What am I missing here?
I did change it a bit, but it works now. Remove the fprintf(stderr,... after verification:
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <errno.h>
#include <unistd.h>
#include <fcntl.h>
#include <signal.h>
#define READ_END 0
#define WRITE_END 1
pid_t popen2(const char **command, int fdarray[]);
pid_t popen2(const char **command, int fdarray[])
{
int p_stdin[2], p_stdout[2];
pid_t pid;
int rc;
if (pipe(p_stdin) != 0 || pipe(p_stdout) != 0) {
return -1;
}
pid = fork();
if (pid < 0) {
return pid;
} else if (pid == 0) {
close(p_stdin[WRITE_END]);
dup2(p_stdin[READ_END], STDIN_FILENO);
close(p_stdin[READ_END]);
close(p_stdout[READ_END]);
dup2(p_stdout[WRITE_END], STDOUT_FILENO);
close(p_stdout[WRITE_END]);
rc = execvp(*command, command);
_exit(EXIT_FAILURE);
}
close(p_stdout[WRITE_END]);
close(p_stdin[READ_END]);
if (fdarray == NULL) {
close(p_stdin[WRITE_END]);
close(p_stdout[READ_END]);
} else {
fdarray[READ_END] = p_stdout[READ_END];
fdarray[WRITE_END] = p_stdin[WRITE_END];
}
return pid;
}
#define BUFF_SIZE 1024
struct buff {
size_t used;
size_t size;
char data[BUFF_SIZE];
}
ibuf = {0,BUFF_SIZE,}
, obuf = {0,BUFF_SIZE,}
;
int readbuff(int fd, struct buff *bp);
int writebuff(int fd, struct buff *bp);
int readbuff(int fd, struct buff *bp)
{
size_t done;
int rc=0;
for (done=0; bp->used < bp->size; bp->used+=rc, done+=rc) {
if (done) break;
fprintf(stderr, "Read(%d,%zu)\n", fd, bp->size - bp->used );
rc = read(fd, bp->data+bp->used, bp->size - bp->used);
if (rc== -1) switch (errno) {
#if (EWOULDBLOCK != EAGAIN)
case EWOULDBLOCK:
#endif
case EAGAIN:
case EINTR: rc=0; continue;
default:
fprintf(stderr, "Error on readbuff: %d: %s\n", errno, strerror(errno));
goto failed;
}
fprintf(stderr, "Readbuff(%d) := %d\n", fd, rc);
if (rc==0) { rc = -1; break; }
}
failed:
return done ? done : rc;
}
int writebuff(int fd, struct buff *bp)
{
size_t done;
int rc= 0;
for (done=0; done < bp->used ; done+=rc) {
if (done) break;
fprintf(stderr, "Write(%d,%zu)\n", fd, bp->used - done);
rc = write(fd, bp->data+done, bp->used - done);
if (rc== -1) switch (errno) {
#if (EWOULDBLOCK != EAGAIN)
case EWOULDBLOCK:
#endif
case EINTR:
case EAGAIN:rc=0; continue;
default:
fprintf(stderr, "Error on writebuff: %d: %s\n", errno, strerror(errno));
goto failed;
}
fprintf(stderr, "Writebuff(%d) := %d\n", fd, rc);
if (rc==0) { rc = -1; break; }
}
failed:
if (done == bp->used ) bp->used =0;
else { memmove(bp->data, bp->data+done, bp->used - done); bp->used -= done; }
return done ? done : rc;
}
int main (void)
{
int pipes[2] = {-1,-1};
int rc1, rc2,err;
char *commands[] = { "tee", "teapot", NULL};
// signal(SIGCHLD, SIG_IGN);
// signal(SIGPIPE, SIG_IGN);
rc1 = popen2( commands, pipes);
err = errno;
fprintf(stderr, "Rc=%d:%d(%s) pipes[0]=%d, pipes[1]=%d\n"
, rc1 , rc1 == -1 ? err : 0
, strerror(rc1 == -1?err:0)
, pipes[0]
, pipes[1]
);
if (rc1 == -1) return EXIT_FAILURE;
while(1) {
fprintf(stderr, "#----------------------------------------\n" );
rc1 = readbuff(STDIN_FILENO, &ibuf);
#if 1
if (rc1 == -1 && ibuf.used ==0) {
fprintf(stderr, "Rc1=%d Close %d\n", rc1, pipes[WRITE_END]);
close(pipes[WRITE_END]);
}
else
#endif
writebuff(pipes[WRITE_END] , &ibuf);
rc2 = readbuff(pipes[READ_END] , &obuf);
writebuff(STDOUT_FILENO, &obuf);
fprintf(stderr, "Rc=%d/%d Ibuf[0]=%zu/%zu, Obuf[0]=%zu/%zu\n"
, rc1, rc2
, ibuf.used, ibuf.size
, obuf.used, obuf.size
);
if (rc1 < 0 && rc2 < 0) break;
}
wait(NULL);
return 0;
}

Resources