Code:
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <sys/sem.h>
#include <sys/shm.h>
#include <sys/ipc.h>
#include <sys/wait.h>
#define ITEM_SIZE 4096
/* define semaphores within the set */
#define SEM_FULL 0
#define SEM_EMPTY 1
#define SEM_LAST_TRANS_SIZE 2
#define SEM_TERMINATED 3
char input_line[50]; /* gather file names from user */
char output_line[50];
char items[ITEM_SIZE];
char buffer[ITEM_SIZE * 10]; /* array of 10 items */
FILE *in_file; /* input = file to read; output = file to write */
FILE *out_file;
union semun
{
int val;
struct semid_ds *buf;
ushort *array;
} seminfo;
struct sembuf Wait_Empty={SEM_EMPTY, -1, 0};
struct sembuf Signal_Empty={SEM_EMPTY, 1, 0};
struct sembuf Wait_Full={SEM_FULL, -1, 0};
struct sembuf Signal_Full={SEM_FULL, 1, 0};
int main(){
int pid;
int terminated_val;
int read_size; /* number of bytes on last read */
/* gather shared memory space */
int shmid;
char * shm_addr;
shmid = shmget(IPC_PRIVATE, ITEM_SIZE * 10, IPC_CREAT); /* creat sh memory */
shm_addr = shmat(shmid, NULL, 0); /* attach sh memory */
/* get the 4 semaphores to be used */
int semid;
semid = semget(IPC_PRIVATE, 4, 0600 | IPC_CREAT);
/* Initialize values for the 4 semaphores */
semctl(semid, SEM_FULL, SETVAL, 0);
semctl(semid, SEM_EMPTY, SETVAL, ITEM_SIZE * 10);
semctl(semid, SEM_LAST_TRANS_SIZE, SETVAL, 0);
semctl(semid, SEM_TERMINATED, SETVAL, 0);
/* gather the input file for the child to read from the user */
fprintf(stderr, "Enter the file name to be copied:");
fgets(input_line, sizeof(input_line), stdin);
if(input_line[strlen(input_line)-1] == '\n') input_line[strlen(input_line)-1] = 0;
/* gather the output file for the parent to put the copy in */
fprintf(stderr, "Enter the file name to be written:");
fgets(output_line, sizeof(output_line), stdin);
if(output_line[strlen(output_line)-1] == '\n') output_line[strlen(output_line)-1] = 0;
/* fork and cross fingers */
pid = fork();
/* parent process responsible for generating the copy "write to the file" */
if(pid == 0){
int out = 0;
/* test if file exists, if not create the file specified by user */
if((out_file = fopen(output_line, "r")) == NULL){
creat(output_line, "w");
fprintf(stderr, "File created\n");
}
/* write to file from buffer */
while(1){
/* wait(full) */
semop(semid, &Wait_Full, 1);
terminated_val = semctl(semid, SEM_TERMINATED, GETVAL);
if(terminated_val == 1){
write(out_file, buffer[out], (unsigned int) read_size);
fprintf(stderr, "File copy complete\n");
fclose(out_file);
semctl(semid, 4, IPC_RMID); /* remove the semaphores */
shmdt(shm_addr); /* detach shared memory for removal */
shmctl(shmid, IPC_RMID, NULL); /* remove shared memory */
return(0);
}
/* write the copy file from the buffer */
write(out_file, buffer[out], (unsigned int) read_size);
/* update the buffer */
out = (out+1)%(ITEM_SIZE*10);
/* signal(empty) */
semop(semid, &Signal_Empty, 1);
}
}
/* child process responsible for reading the file and passing it to the buffer */
else if (pid > 0){
int in = 0;
/* file entered by the user was not found */
if((in_file = fopen(input_line, "r")) == NULL){
fprintf(stderr, "File could not be opened\n");
perror("fopen");
}
/* file specified by user was found */
else
fprintf(stderr, "File Found\n");
while(1){
/* wait(empty) */
semop(semid, &Wait_Empty, 1);
/* read ITEM_SIZE into the buffer */
read_size = read(in_file, buffer[in], ITEM_SIZE);
fprintf(stderr, "%d\n", read_size);
/*update the buffer */
in = (in+1)%(ITEM_SIZE*10);
/* read_size must not be negative or error */
if(read_size < 0){
fprintf(stderr, "something bad happend\n");
exit(8);
}
/* end of file */
else if(read_size > 0 && read_size < ITEM_SIZE){
/* last of the file set last-transfer-size semaphore to size of file left */
semctl(semid, SEM_LAST_TRANS_SIZE, SETVAL, read_size);
fclose(in_file);
/* set the terminated semaphore to 1 */
semctl(semid, SEM_TERMINATED, SETVAL, 1);
semop(semid, &Signal_Full, 1);
}
/* signal(full) */
semop(semid, &Signal_Full, 1);
}
}
/* Oops fork did not happen */
else perror("fork\n");
}