How to get unbuffered output from popen & fgets - linux

I'm using popen to execute a command and read the output. I'm setting the file descriptor to non-blocking mode so that I can put in my own timeout, as follows:
auto stream = popen(cmd.c_str(), "r");
int fd = fileno(stream);
int flags = fcntl(fd, F_GETFL, 0);
flags |= O_NONBLOCK;
fcntl(fd, F_SETFL, flags);
while(!feof(stream)) {
if(fgets(buffer, MAX_BUF, stream) != NULL) {
// do something with buffer...
}
sleep(10);
}
pclose(stream);
This works just fine, except that fgets keeps returning NULL, until the program has finished executing, at which time it returns all the output as expected.
In other words, even if the program immediately outputs some text and a newline to the stdout, my loop doesn't read it immediately; it only sees it later.
In the documentation for popen I see:
Note that output popen() streams are block buffered by default.
I've tried a few things to turn off buffering (ex. setvbuf(stream, NULL, _IONBF, 0)) , but so far no luck.
How do I turn off buffering so that I can read the output in real-time?
Thank you!

A solution based on something like select() would be more accurate and flexible. Try this :
#include <stdio.h>
#include <unistd.h>
#include <errno.h>
#include <sys/select.h>
void read_cmd(const char *cmd)
{
FILE *stream;
int fd;
int flags;
char buffer[1024];
fd_set fdset;
struct timeval timeout;
int rc;
int eof;
stream = popen(cmd, "r");
fd = fileno(stream);
eof = 0;
while(!eof) {
timeout.tv_sec = 10; // 10 seconds
timeout.tv_usec = 0;
FD_ZERO(&fdset);
FD_SET(fd, &fdset);
rc = select(fd + 1, &fdset, 0, 0, &timeout);
switch(rc) {
case -1: {
// Error
if (errno != EINTR) {
fprintf(stderr, "select(): error '%m' (%d)\n", errno);
}
return;
}
break;
case 0: {
// Timeout
printf("Timeout\n");
}
break;
case 1: {
// Something to read
rc = read(fd, buffer, sizeof(buffer) - 1);
if (rc > 0) {
buffer[rc] = '\0';
printf("%s", buffer);
fflush(stdout);
}
if (rc < 0) {
fprintf(stderr, "read(): error '%m' (%d)\n", errno);
eof = 1;
}
if (0 == rc) {
// End of file
eof = 1;
}
}
break;
} // End switch
} // End while
pclose(stream);
}
int main(int ac, char *av[])
{
read_cmd(av[1]);
return 0;
} // main

Related

why the system hang when I write characters to my dummy character device?

I am learning how to write Linux Device Driver.
I wrote a dummy character device driver, implemented open, release, write, read in fops;
When I read from device , everything was ok;
When I wrote to device by "echo xx > ", the OS was hang.
Even I comment out all codes in write function except pr_alert and return statements, It still hangs;
Could anybody help me figure it out?
#include <linux/init.h>
#include <linux/types.h>
#include <linux/module.h>
#include <linux/mutex.h>
#include <linux/cdev.h>
#include <linux/fs.h>
#include <linux/slab.h>
#include <linux/string.h>
struct hello_dev
{
char *buffer;
int length;
dev_t dev;
struct mutex lock;
struct cdev *pcdev;
};
struct hello_dev *pHelloDev;
int open_device(struct inode *pinode, struct file *filp)
{
filp->private_data = pHelloDev;
return 0;
}
int close_device(struct inode *pinode, struct file *filp)
{
struct hello_dev *pDev = filp->private_data;
if (pDev->buffer != NULL)
kfree(pDev->buffer);
pDev->buffer = NULL;
return 0;
}
ssize_t read_device(struct file *filp, char __user *buffer, size_t len, loff_t *loff)
{
pr_alert("read\n");
struct hello_dev *pDev = filp->private_data;
mutex_lock(&pDev->lock);
if (pDev->buffer == NULL)
{
mutex_unlock(&pDev->lock);
return 0;
}
int length = strlen(pDev->buffer);
// offset max than strlen in buffer, return
if (*loff > (length - 1))
{
mutex_unlock(&pDev->lock);
return 0;
} else {
// available to read
int len2read = length - *loff;
if (len < len2read)
{// buffer length less than available data
len2read = len;
}
int read = copy_to_user(buffer, pDev->buffer + *loff, len2read);
if (read)
{
*loff = *loff + read;
mutex_unlock(&pDev->lock);
return read;
} else {
*loff = *loff + len2read;
mutex_unlock(&pDev->lock);
return len2read;
}
}
}
ssize_t write_device(struct file *filp , const char __user *buffer, size_t len, loff_t* loff) {
pr_alert("write %s\n", buffer);
// struct hello_dev *pDev = filp->private_data;
// mutex_lock(&pDev->lock);
// if(pDev->buffer == NULL) {
// pDev->buffer = kmalloc(100, GFP_KERNEL);
// pDev->length = 100;
// }
// copy_from_user(pDev->buffer, buffer, len);
// *loff = *loff + len;
// mutex_unlock(&pDev->lock);
return len;
}
struct file_operations fops = {
.open = open_device,
.release = close_device,
.read = read_device,
.write = write_device
};
int init_device(void)
{
pr_alert("init device\n");
pHelloDev = kmalloc(sizeof(struct hello_dev), GFP_KERNEL);
pHelloDev->buffer = NULL;
pHelloDev->length = 0;
int ret = alloc_chrdev_region(&pHelloDev->dev, 0, 1, "hello");
if (ret)
goto alloc_error;
if (pHelloDev == NULL)
goto kmalloc_error;
pHelloDev->pcdev = cdev_alloc();
pHelloDev->pcdev->ops = &fops;
mutex_init(&pHelloDev->lock);
ret = cdev_add(pHelloDev->pcdev, pHelloDev->dev, 1);
if (ret)
goto cdev_add_error;
return 0;
alloc_error:
pr_alert("alloc_chrdev_region error, %d\n", ret);
return ret;
kmalloc_error:
pr_alert("alloc struct hello_dev error");
return -ENOMEM;
cdev_add_error:
pr_alert("cdev_add error, %d\n", ret);
return ret;
}
void cleanup_device(void)
{
pr_alert("unload ko\n");
cdev_del(pHelloDev->pcdev);
unregister_chrdev_region(pHelloDev->dev, 1);
}
MODULE_LICENSE("GPL");
module_init(init_device);
module_exit(cleanup_device);
I found why write to device hangs.
//this statements has problem
//maybe there is no \0 in buffer
//so I print it out, it will hang
//I wrote a program to write something to device
//and used strace to trace system call made by this program
//and found it hangs at write(...) system call
//and there was nothing printed out
//so, it must be this statement causing the problem
//when I removed this statement, everything was ok
pr_alert("write %s\n", buffer);

fanotify: is it possible to monitor whole filesystem and write few logs/config in monitored filesystem by same process?

My system gets hanged, if I try to log something in file by same process.
Actually I wanted to monitor entire filesystem ("/") with fanotify and also want to log errors in case any in "/tmp", but it results in system hang.
Please find below code:
#include <errno.h>
#include <fcntl.h>
#include <limits.h>
#include <poll.h>
#include <stdio.h>
#include <stdlib.h>
#include <sys/fanotify.h>
#include <unistd.h>
#include <string.h>
static void
handle_events(int fd)
{
const struct fanotify_event_metadata *metadata;
struct fanotify_event_metadata buf[200];
ssize_t len;
char path[PATH_MAX];
ssize_t path_len;
char procfd_path[PATH_MAX];
struct fanotify_response response;
//Loop while events can be read from fanotify file descriptor
for (;;)
{
//Read some events
len = read(fd, (void *) &buf, sizeof(buf));
if (len == -1 && errno != EAGAIN)
{
system("echo 'Read error' >> /tmp/fanotify.txt");
exit(EXIT_FAILURE);
}
//Check if end of available data reached
if (len <= 0)
break;
//Point to the first event in the buffer
metadata = buf;
//Loop over all events in the buffer
while (FAN_EVENT_OK(metadata, len))
{
//Check that run-time and compile-time structures match
if (metadata->vers != FANOTIFY_METADATA_VERSION)
{
system("echo 'Mismatch of fanotify metadata version' >> /tmp/fanotify.txt");
exit(EXIT_FAILURE);
}
/* metadata->fd contains either FAN_NOFD, indicating a
queue overflow, or a file descriptor (a nonnegative
integer). Here, we simply ignore queue overflow. */
if (metadata->fd >= 0)
{
//Handle open permission event
if (metadata->mask & FAN_OPEN_PERM)
{
//Allow file to be opened
response.fd = metadata->fd;
response.response = FAN_ALLOW;
write(fd, &response,sizeof(struct fanotify_response));
system("echo 'FAN_OPEN_PERM:' >> /tmp/fanotify.txt");
}
//Handle closing of writable file event
if (metadata->mask & FAN_CLOSE_WRITE)
{
system("echo 'FAN_CLOSE_WRITE:' >> /tmp/fanotify.txt");
}
//Retrieve and print pathname of the accessed file
snprintf(procfd_path, sizeof(procfd_path),
"/proc/self/fd/%d", metadata->fd);
path_len = readlink(procfd_path, path,
sizeof(path) - 1);
if (path_len == -1)
{
system("echo 'readlink error' >> /tmp/fanotify.txt");
exit(EXIT_FAILURE);
}
path[path_len] = '\0';
close(metadata->fd);
char szLog[256] = {'\0'};
snprintf(szLog, sizeof(szLog), "echo 'File %s' >> /tmp/fanotify.txt", path);
system(szLog);
//Close the file descriptor of the event
}
//Advance to next event
metadata = FAN_EVENT_NEXT(metadata, len);
}
}
}
Here is main function from where I am calling handle_events
int
main(int argc, char *argv[])
{
char buf;
int fd, poll_num;
nfds_t nfds;
struct pollfd fds[2];
char szMountCommand[1024] = {'\0'};
uint64_t uiMask = FAN_OPEN_PERM | FAN_CLOSE_WRITE | FAN_EVENT_ON_CHILD;
//Check mount point is supplied
if (argc != 2) {
fprintf(stderr, "Usage: %s MOUNT\n", argv[0]);
exit(EXIT_FAILURE);
}
system("echo 'Press enter key to terminate' >> /tmp/fanotify.txt");
//Create the file descriptor for accessing the fanotify API
fd = fanotify_init(FAN_CLOEXEC | FAN_CLASS_CONTENT | FAN_NONBLOCK,
O_RDONLY | O_LARGEFILE);
if (fd == -1) {
system("echo 'fanotify_init failed.' >> /tmp/fanotify.txt");
exit(EXIT_FAILURE);
}
/* Mark the mount for:
- permission events before opening files
- notification events after closing a write-enabled
file descriptor */
snprintf(szMountCommand, sizeof(szMountCommand), "mount --bind %s %s", argv[1], argv[1]);
system(szMountCommand);
if (fanotify_mark(fd, FAN_MARK_ADD | FAN_MARK_MOUNT, uiMask, 0, argv[1]) == -1)
{
system("echo 'fanotify_mark failed.' >> /tmp/fanotify.txt");
exit(EXIT_FAILURE);
}
system("echo 'Monitoring:' >> /tmp/fanotify.txt");
//Prepare for polling
nfds = 2;
//Console input
fds[0].fd = STDIN_FILENO;
fds[0].events = POLLIN;
//Fanotify input
fds[1].fd = fd;
fds[1].events = POLLIN;
//This is the loop to wait for incoming events
system("echo 'Listening for events:' >> /tmp/fanotify.txt");
while (1) {
poll_num = poll(fds, nfds, -1);
if (poll_num == -1) {
if (errno == EINTR) //Interrupted by a signal
continue; // Restart poll()
system("echo 'poll failed.' >> /tmp/fanotify.txt");
exit(EXIT_FAILURE);
}
if (poll_num > 0) {
if (fds[0].revents & POLLIN) {
//Console input is available: empty stdin and quit
while (read(STDIN_FILENO, &buf, 1) > 0 && buf != '\n')
continue;
break;
}
if (fds[1].revents & POLLIN) {
//Fanotify events are available
handle_events(fd);
}
}
}
system("echo 'Listening for events stopped.' >> /tmp/fanotify.txt");
exit(EXIT_SUCCESS);
}
That's an infinite loop!
Consider you get a notification (due to some external change) and want to write that to the same filesystem. So, it would generate another notification (due to the logging). you want to write the new notification. That leads to another notification. So that is an endless loop.
You shuold use another mounted filesystem for logging or monitor only a specific path.

Named Pipe, Communication between 2 children

I have a problem with my code. I want to make communication between 2 children process. One of them is a server, which opens a file and sends each letter to the second process. The second process is counting letters and it should make a new file and save results. I have problems with the last step because the first process gonna finish faster than the second, what causes the end of the program. I have no idea how fix it. Looking for some tips :).
Here you got result.
My code:
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <errno.h>
#include <fcntl.h>
#include <signal.h>
#include <string.h>
//stale
#define FIFO "my_fifo"
#define SIZE 26
//zmienne globalne
int desk; //deskryptor pliku
int tab[SIZE];
//prototypy funkcji
void parentKillAll();
void server(FILE * file);
void client();
void cleanUp(FILE * file);
int checkEntryData(int argc, char *argv);
void replaceTabWithZero(int * tab);
void countLetters(int * tab, char ch);
void saveResults(int * tab, char *title);
void showTab(int * tab);
int main(int argc, char *argv[]) {
if (!checkEntryData(argc, argv[1]))
return 1;
replaceTabWithZero(tab);
FILE *file = fopen(argv[1], "r");
umask(0);
mkfifo(FIFO, 0666);
if (file) {
if (fork() == 0) {
server(file);
exit(0);
} else if (fork() == 0) {
client();
saveResults(tab, strcat(argv[1], "Result"));
showTab(tab);
exit(0);
} else {
cleanUp(file);
parentKillAll();
}
} else {
perror("Error");
}
return 0;
}
void parentKillAll() {
sleep(1);
kill(0, SIGKILL);
exit(0);
}
void server(FILE * file) {
char ch;
while ((ch = fgetc(file)) != EOF) {
desk = open(FIFO, O_WRONLY);
write(desk, &ch, 1);
}
}
void client() {
char ch;
while (1) {
desk = open(FIFO, O_RDONLY);
read(desk, &ch, 1);
countLetters(tab, ch);
printf("%c", ch);
}
}
void cleanUp(FILE *file) {
wait(0);
fclose(file);
close(desk);
}
int checkEntryData(int argc, char *argv) {
if (argc < 2) {
fprintf(stderr, "Nie poprawna ilosc argumentow\n");
return 0;
}
if (access(argv, F_OK)) {
fprintf(stderr, "Podany plik \'%s\' nie istnieje\n", argv);
return 0;
}
if (access(argv, R_OK)) {
fprintf(stderr, "Brak uprawnien do odczytu pliku \'%s\'\n", argv);
return 0;
}
return 1;
}
void replaceTabWithZero(int * tab) {
for (int i = 0; i < SIZE; i++)
tab[i] = 0;
}
void countLetters(int *tab, char ch) {
int chVal = ch;
if (chVal > 92)
chVal -= 32;
if (chVal > 64 && chVal < 91)
tab[chVal-65] += 1;
}
void saveResults(int *tab, char * title) {
FILE *plik = fopen(title, "w");
if (plik) {
for (int i = 0; i < SIZE; i++)
fprintf(plik, "%c - %d\n", (i+97), tab[i]);
} else {
perror("Error");
}
fclose(plik);
}
void showTab(int * tab) {
for (int i = 0; i < SIZE; i++)
printf("\n%d", tab[i]);
}
The real problem is that the client process can never finish, because it runs an infinite while(1) loop without any exit conditions.
You should rewrite it so that it exits after reading all available data:
void client() {
char ch;
// Open the fifo only once, instead of once per character
desk = open(FIFO, O_RDONLY);
// Loop until there is no more data to read
while(read(desk, &ch, 1) > 0) {
countLetters(tab, ch);
printf("%c", ch);
}
}
This is technically sufficient to make it work, but you should also look into a series of other issues:
You should have two wait(0) calls so that you wait for both processes, and you shouldn't try to kill anything.
The server process should only be opening the fifo once, not once per character.
You should be comparing fgetc output to EOF before forcing the value into a char. Since you do it after, running your program on a ISO-8859-1 terminal will cause it to confuse EOF and the letter ΓΏ
You are using strcat on argv[1], even though you don't know how much space that array has. You should use your own buffer of a known length.
You should check the return value of all your system calls to ensure they succeed. Checking with access and then assuming it'll be fine is not as good since calls can fail for other reasons.
Canonical Unix behavior is to exit with 0 for success, and >= 1 for error.
It's good practice to use a larger buffer (e.g. 65536 bytes instead of 1) when using read/write directly. stdio functions like fgetc already uses a larger buffer behind the scenes.
Using a named pipe obviously works, but since you spawn both processes it would be more natural to use an unnamed one.

Thread issue in socket Programming

I have the following codes..
server.c
#include <stdio.h>
#include "./../linux.h"
#include "./tcp.h"
#include <pthread.h>
static int clients = 0;
static int* memptr = NULL;
void serve(void*);
int* push(int* memptr, int nsfd) {
clients++;
if (clients == 1)
memptr = (int*)malloc(sizeof(int) * clients);
else
memptr = (int*)realloc(memptr, sizeof(int) * clients);
memptr[clients - 1] = nsfd;
return memptr;
}
int main(int argc, char** argv) {
pthread_t thread[2];
int threadCount = 0;
if (argc != 3){
printf("\nUsage: ./server port_number maximum_clients\n");
return 1;
}
static struct sockaddr_in sock, sock_client;
int len, new_sock_fd;
int sock_fd = socket(PF_INET, SOCK_STREAM, 0);
if (sock_fd == -1){
perror("socket");
exit(1);
}
sock.sin_family = PF_INET;
sock.sin_port = htons(atoi(argv[1]));
sock.sin_addr.s_addr = inet_addr("0.0.0.0");
len = sizeof(sock);
if ( bind(sock_fd, (struct sockaddr *)&sock, len) == -1){
perror("bind");
exit(1);
}
if ( listen(sock_fd, atoi(argv[2])) == -1){
perror("listen");
exit(1);
}
while(1) {
new_sock_fd = accept(sock_fd, (struct sockaddr *)&sock_client, (socklen_t *)&len);
memptr = push(memptr, new_sock_fd);
if (new_sock_fd == -1){
perror("accept");
exit(1);
}
pthread_create(&(thread[threadCount]), NULL, (void*)&serve, (void *)&new_sock_fd);
pthread_join(thread[threadCount++], NULL);
printf("threadCount = %d\n", threadCount);
sleep(1);
}
return 0;
}
void serve(void* fd){
int* new_sock_fd = (int*)fd;
Packet packet;
while(1){
bzero(&packet, sizeof(packet));
read(*new_sock_fd , &packet, sizeof(packet));
printf("%d\n", *new_sock_fd);
//printf("recipientId = %d\n", packet.recipientId);
// printf("message = %s\n", packet.data);
write(memptr[packet.recipientId - 1], packet.data, 1024);
}
pthread_exit(0);
}
and the tcp.h looks like
#ifndef __TCP_H__
# define __TCP_H__
typedef struct {
int recipientId; // this is the reciever ID
char data[1024]; // this is the main data part
}Packet;
#endif /* __TCP_H__ */
and each client.h looks like this
#include <stdio.h>
#include "./../linux.h"
#include "./tcp.h"
#include <pthread.h>
void print(void);
void scan(void);
int sock_fd;
int main(int argc, char** argv) {
if (argc != 3){
printf("\nUsage: ./client port_number server_ip\n");
return 1;
}
static struct sockaddr_in sock;
int len;
pthread_t thread1, thread2;
sock_fd = socket(PF_INET, SOCK_STREAM, 0);
if (sock_fd == -1){
perror("socket");
exit(1);
}
sock.sin_family = PF_INET;
sock.sin_port = htons(atoi(argv[1]));
sock.sin_addr.s_addr = inet_addr(argv[2]);
len = sizeof(sock);
if ( connect(sock_fd, (struct sockaddr *)&sock , len) == -1 ){
perror("connect");
exit(1);
}
pthread_create(&thread1, NULL, (void*)&print, NULL);
pthread_create(&thread2, NULL, (void*)&scan, NULL);
pthread_join(thread1, NULL);
pthread_join(thread2, NULL);
return 0;
}
void print(){
char messege[1024];
while(1){
if (read(sock_fd, messege, 1024) == -1){
perror("read");
return;
}
printf("messege = %s\n", messege);
}
pthread_exit(0);
}
void scan(void){
Packet packet;
while(1){
printf("Enter the reciver ID: ");
scanf("%d", &packet.recipientId);
printf("Enter the data: ");
scanf("%s", packet.data);
if ( write(sock_fd, &packet, sizeof(packet)) == -1) {
perror("read");
return;
}
}
pthread_exit(0);
}
Now the problems are
when I am running the server & the in 2 terminals, 2 clients after each client is accepted threadCount should be printed at the server end but it is not printing. It means the execution stops/skips after the first pthread_join but WHY ??
After connecting two threads, when I sent the data from 1st client to the 1st client itself, it works but not from the 1st client to the 2nd client..rather it is sending to the server terminal window. WHY ??
When sent from the second client nothing works ( sending itself or client 1)..WHY??
Please help..And thanks for patiently reading all the codes above.
TCP is a byte stream protocol, not a message protocol. You are calling TCP functions and expecting them to send or receive messages. They don't. If you want to send or receive messages, you have to implement a message protocol, write functions that send and receive messages, and then call those functions.
if (read(sock_fd, messege, 1024) == -1){
perror("read");
return;
}
printf("messege = %s\n", messege);
This call to printf is a disaster. The %s format specifier is for C-style strings, not arbitrary chunks of bytes received from a byte stream. For the most obvious way to see how bad this is, consider this --- how should printf decide how many bytes to print? You threw away the value read returned after you compared it to -1, so you have no idea how many bytes you received.
I'm sure there are other issues with your code, but the fact that the fundamental design is broken makes it not worth fixing those issues. Instead, design a message protocol and implement that.

Message queue/shared memory method

I have a bit of a problem in using IPC (inter-process communication) program below.
Please let me explain:
I want to pass Linux commands such as "ls" or "wc file.txt"
from a parent to a child to execute using the message queue, and
then have the child returning the command outputs back to
the parent process using shared memory method.
But this is what I got: The parent process always got the output 1 step behind;
in the following fashion:
Step1) ls file.txt
(Nothing showed up.)
Step2) wc file.txt
(Output of earlier command "ls file.txt" showed up here instead.)
Step 3) cat file.txt
(Output of earlier command "wc file.txt" showed up instead.)
Any help is appreciated.
To compile: gcc -o program ./program.c
To run: -./program -v
Code:
#define BUFSZ 512
#define ERRBUFSZ 512
#define TIMEOUT_TIMEDIO 20
#define SHM_SIZE 5120
#include <stdio.h>
#include <errno.h>
#include <unistd.h>
#include <stdlib.h>
#include <string.h>
#include <signal.h>
#include <setjmp.h>
#include <sys/wait.h>
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/shm.h>
static sigjmp_buf jmpbuf;
int timed_io(char* buf, int len, FILE* rfp, int sec);
static void sigalrm_handler(int signo);
void do_cmd(char *buf, int len, int linenum, char *errbuf);
int parse_cmd(char *buf, char **vbuf, char *errbuf);
int process_cmd_ipc(char *argv, int linenum, char *errbuf);
struct my_msgbuf {
long mtype;
char mtext[256];
};
static void sigalrm_handler(int signo)
{
siglongjmp(jmpbuf, 1);
}
int timed_io(char* buf, int len, FILE* rfp, int sec)
{
struct sigaction nsigaction[1];
struct sigaction osigaction[1];
int prev_alrm;
int st = 0;
if(sigsetjmp(jmpbuf, 1) == 0)
{
nsigaction->sa_handler = sigalrm_handler;
sigemptyset(&nsigaction->sa_mask);
nsigaction->sa_flags = SA_RESTART;
prev_alrm = alarm(0);
sigaction(SIGALRM, nsigaction, osigaction);
alarm(sec);
if (fgets(buf, len, rfp) == NULL)
st = -1; // EOF
buf[strlen(buf) - 1] = 0;
}
else { st = -2; } // Time-out
alarm(0); // Reset old alarm and handler
sigaction(SIGALRM, osigaction, 0);
return st;
}
int process_cmd_ipc(char *argv, int linenum, char* errbuf)
{
struct my_msgbuf buf;
int msqid, msqid_parent, st, shmid, str_len;
key_t key, key_shm;
char* shared_buf;
FILE *fd;
// create key for shared memory segment
if ((key_shm = ftok("shm_key.txt", 'R')) == -1) {
perror("ftok");
exit(1);
}
// Connect to shared memory segment
if ((shmid = shmget(key_shm, SHM_SIZE, 0644 | IPC_CREAT)) == -1)
{
perror("shmget");
exit(1);
}
// Attach to shared memory segment
shared_buf = shmat(shmid, (void *) 0, 0);
if (shared_buf == (char *) (-1)) {
perror("shmat");
exit(1);
}
// End of shared memory section` //
// Begin: message queue section
pid_t cpid=fork();
if (cpid<0) {
fprintf(stderr,"ERR: \"fork\" error! (Line=%d)\n", linenum);
exit (-1);
} else if (cpid==0) // child process
{ // Begin: message queue
if ((key = ftok("mysh.c", 'B')) == -1) {
perror("ftok");
exit(1);
}
if ((msqid = msgget(key, 0644)) == -1) {
perror("msgget from child");
exit(1);
}
memset(buf.mtext, 0, sizeof(buf.mtext)); // Clear buffer
if(msgrcv(msqid, (struct msgbuf*) &buf, sizeof(buf), 0,0) == -1)
{
perror("msgrcv");
exit(1);
}
// End: message queue
// begin: shared memory segment
memset(shared_buf, 0, SHM_SIZE); // zeroize shared_buf
fd = popen(buf.mtext, "r");
str_len = 0;
while(fgets(shared_buf + str_len, SHM_SIZE, fd) != NULL)
{ str_len = strlen(shared_buf); }
pclose(fd);
// end: shared memory segment
}
else { // parent
// Begin - message queue
if ((key = ftok("mysh.c", 'B')) == -1) {
perror("ftok");
exit(1);
}
if ((msqid_parent = msgget(key, 0644 | IPC_CREAT)) == -1) {
perror("msgget from parent");
exit(1);
}
buf.mtype = 1;
strncpy(buf.mtext, argv, strlen(argv));
if(msgsnd(msqid_parent, (struct my_msgbuf*) &buf, strlen(buf.mtext), 0) == -1)
perror("msgsnd");
// End - message queue
// Begin - shared memory
// usleep(10000);
printf("%s", shared_buf);
// End - shared memory
} // if-else fork
}
int parse_cmd(char *buf, char **vbuf, char *errbuf)
{
int i=0;
char *delim=" ,\t\n";
char *tok;
tok=strtok(buf,delim);
while (tok) {
vbuf[i]=(char *)malloc(BUFSZ*sizeof(char));
strcpy(vbuf[i],tok);
tok=strtok(NULL,delim);
i++;
}
vbuf[i]=0;
return i;
}
void do_cmd(char *buf, int len, int linenum, char *errbuf) {
int i=0; int numargs;
char *vbuf[128];
char* copy = (char *) malloc(strlen(buf) + 1);
int maxargs=sizeof(vbuf)/sizeof(char *);
strcpy(copy, buf);
numargs = parse_cmd(copy,vbuf,errbuf);
process_cmd_ipc(buf,linenum, errbuf);
for (i=0;i<numargs; i++) { free(vbuf[i]); }
free(copy);
copy = NULL;
return;
}
int main(int argc, char **argv)
{
int i; int st; int linenum=0;
char *buf=(char *)malloc(BUFSZ*sizeof(char));
char *errbuf=(char *)malloc(ERRBUFSZ*sizeof(char));
char *mysh = "";
FILE *rfp=stdin;
if (isatty(fileno(rfp))) {
mysh = "mysh (Ctrl-C to exit)>";
fprintf(stderr,"%s",mysh);
}
while(1)
{
st = timed_io(buf, BUFSZ, stdin, TIMEOUT_TIMEDIO);
if (st != 0)
{
fprintf(stderr, "ERR: No input %s (Status=%d)\n", errbuf, st);
return -1;
}
else
{
linenum++;
if (*buf)
{ do_cmd(buf, BUFSZ, linenum,errbuf); }
if (mysh)
fprintf(stderr,"%s",mysh);
}
}
}

Resources