Why can't I simulate auto-completion with '\t' in busybox - c

I want to use "yp\t\n\0" to run “ypdomainname” command by exploiting auto-completion in busybox, but it failed. my code and result are below:
#include <stdio.h>
#include <unistd.h>
#include <string.h>
#include <sys/wait.h>
#include <fcntl.h>
#define DEFAULT_BUSYBOX_PATH "/bin/busybox"
#define MAX_BUF 1000
int main()
{
int fd[2];
pid_t pid;
FILE *file;
int status;
if(pipe(fd) < 0){
fprintf(stderr, "pipe error!\n");
return -1;
}
if((pid = fork()) < 0){
fprintf(stderr, "pipe error!\n");
}else if(pid == 0){ //child
close(fd[1]);
int fd_output;
fd_output = open("result", O_CREAT | O_RDWR, 777);
if(fd_output != STDOUT_FILENO){
if(dup2(fd_output, STDOUT_FILENO) != STDOUT_FILENO)
fprintf(stderr, "dup2 error to stdout\n");
}
if(fd[0] != STDIN_FILENO){
if(dup2(fd[0], STDIN_FILENO) != STDIN_FILENO)
fprintf(stderr, "dup2 error to stdin\n");
}
execl(DEFAULT_BUSYBOX_PATH, DEFAULT_BUSYBOX_PATH, "ash", NULL);
close(fd[0]);
close(fd_output);
return 0;
}else{ //parent
close(fd[0]);
char buf[MAX_BUF] = "yp";
buf[2] = '\t';
buf[3] = '\n';
buf[4] = '\0';
write(fd[1], buf, strlen(buf));
close(fd[1]);
return 0;
}
}
Result of my code
What makes me confused is that the character is not changed in function lineedit_read_key() in file lineedit.c and it will run the function input_tab() when the character is '\t'.
input_tab will be executed when character is '\t'
Recently, i took some time to learn about terminal to simulate auto-completion, but i still failed. My code is below:
#include <stdio.h>
#include <stdlib.h>
#include <fcntl.h>
#include <unistd.h>
#include <string.h>
#include <sys/wait.h>
#include <fcntl.h>
#include <termios.h>
#include <errno.h>
#include <signal.h>
#include <pty.h>
#define DEFAULT_BUSYBOX_PATH "/bin/busybox"
#define MAX_BUF 1000
#define BUFFSIZE 512
typedef void Sigfunc(int);
static void sig_term(int);
static volatile sig_atomic_t sigcaught;
ssize_t writen(int fd, const void *ptr, size_t n){
size_t nleft;
ssize_t nwritten;
nleft = n;
while(nleft > 0){
if((nwritten = write(fd, ptr, nleft)) < 0){
if(nleft == n){
return(-1);
}else{
break;
}
}else if(nwritten == 0) {
break;
}
nleft -= nwritten;
ptr += nwritten;
}
return(n - nleft);
}
Sigfunc *signal_intr(int signo, Sigfunc *func){
struct sigaction act;
struct sigaction oact;
act.sa_handler = func;
sigemptyset(&act.sa_mask);
act.sa_flags = 0;
#ifdef SA_INTERRUPT
act.sa_flags |= SA_INTERRUPT;
#endif
if (sigaction(signo, &act, &oact) < 0)
return(SIG_ERR);
return(oact.sa_handler);
}
int ptym_open(char *pts_name, int pts_namesz)
{
char ptr[50];
int fdm;
int err;
if((fdm = posix_openpt(O_RDWR)) < 0){
return(-1);
}
if(grantpt(fdm) < 0){
goto errout;
}
if(unlockpt(fdm) < 0){
goto errout;
}
if(ptsname_r(fdm, ptr, 50) != 0){
goto errout;
}
strncpy(pts_name, ptr, pts_namesz);
pts_name[pts_namesz - 1] = '\0';
return(fdm); /* return fd of master */
errout:
err = errno;
close(fdm);
errno = err;
return(-1);
}
int ptys_open(char *pts_name){
int fds;
if((fds = open(pts_name, O_RDWR)) < 0)
return(-1);
return(fds);
}
pid_t pty_fork(int *ptrfdm, char *slave_name, int slave_namesz, const struct termios *slave_termios, const struct winsize *slave_winsize){
int fdm, fds;
pid_t pid;
char pts_name[20];
if((fdm = ptym_open(pts_name, sizeof(pts_name))) < 0){
fprintf(stderr, "can't open master pty: %s, error %d", pts_name, fdm);
}
if(slave_name != NULL) {
strncpy(slave_name, pts_name, slave_namesz);
slave_name[slave_namesz - 1] = '\0';
}
if((pid = fork()) < 0) {
return(-1);
}else if (pid == 0) { /* child */
if(setsid() < 0){
fprintf(stderr, "setsid error");
}
if((fds = ptys_open(pts_name)) < 0){
fprintf(stderr, "can't open slave pty");
}
close(fdm);
if(slave_termios != NULL) {
if (tcsetattr(fds, TCSANOW, slave_termios) < 0)
fprintf(stderr, "tcsetattr error on slave pty");
}
if(slave_winsize != NULL) {
if (ioctl(fds, TIOCSWINSZ, slave_winsize) < 0)
fprintf(stderr, "TIOCSWINSZ error on slave pty");
}
if(dup2(fds, STDIN_FILENO) != STDIN_FILENO){
fprintf(stderr, "dup2 error to stdin");
}
if(dup2(fds, STDOUT_FILENO) != STDOUT_FILENO){
fprintf(stderr, "dup2 error to stdout");
}
if(dup2(fds, STDERR_FILENO) != STDERR_FILENO){
fprintf(stderr, "dup2 error to stderr");
}
if(fds != STDIN_FILENO && fds != STDOUT_FILENO && fds != STDERR_FILENO){
close(fds);
}
return(0);
} else { /* parent */
*ptrfdm = fdm;
return(pid);
}
}
void loop(int ptym, int ignoreeof)
{
pid_t child;
int nread;
char buf[BUFFSIZE];
if((child = fork()) < 0) {
fprintf(stderr, "fork error");
}else if(child == 0) {
/*for ( ; ; ){
if((nread = read(STDIN_FILENO, buf, BUFFSIZE)) < 0){
fprintf(stderr, "read error from stdin");
}else if(nread == 0){
break;
}
if(writen(ptym, buf, nread) != nread)
fprintf(stderr, "writen error to master pty");
}*/
char *temp_buf = "yp\t\n";
if(writen(ptym, temp_buf, strlen(temp_buf)) != strlen(temp_buf)){
fprintf(stderr, "writen error to master pty");
}
if(ignoreeof == 0){
kill(getppid(), SIGTERM);
}
exit(0);
}
if (signal_intr(SIGTERM, sig_term) == SIG_ERR)
fprintf(stderr, "signal_intr error for SIGTERM");
for( ; ; ){
if ((nread = read(ptym, buf, BUFFSIZE)) <= 0){
}
//printf("nread = %d\n", nread);
if (writen(STDOUT_FILENO, buf, nread) != nread){
fprintf(stderr, "writen error to stdout");
}
}
if (sigcaught == 0){
printf("sigcaught == 0 and kill child\n");
kill(child, SIGTERM);
}
}
static void sig_term(int signo)
{
sigcaught = 1;
}
int main(int argc, char *argv[]){
int fd[2];
pid_t pid;
FILE *file;
int status;
int fdm;
int ignoreeof;
char slave_name[40];
struct termios orig_termios;
struct winsize size;
pid = pty_fork(&fdm, slave_name, sizeof(slave_name), &orig_termios, &size);
if(pid < 0){
fprintf(stderr, "fork error!\n");
}else if(pid == 0){ //child
if(execl(DEFAULT_BUSYBOX_PATH, DEFAULT_BUSYBOX_PATH, "ash", NULL) < 0){
fprintf(stderr, "can't execute: %s", DEFAULT_BUSYBOX_PATH);
}
/*if(execvp(argv[1], &argv[1]) < 0){
fprintf(stderr, "can't execute: %s", argv[1]);
}*/
}
loop(fdm, ignoreeof);
}
like the result of my first try, the result is: ash: yp: not found.

Your code fails because a pipe is not a terminal. Many programs will use isatty(3) and alike to detect if the standard input is connected to a terminal and adjust their behaviour depending on the result.
What you can do is to open a pseudo terminal pair using openpty(3) and run the command with the slave duplicated to its standard input, output and error descriptors, and using the master to communicate with it. Unfortunately I have no time right now writing a full solution as it is rather intricate; I've done it ever in Python and it was tricky even there.

Related

Inappropriate ioctl for device and no job control when using a pty

To lay the groundwork for a future project I'm creating a program that runs bash via pseudo terminals, simply forwarding anything it receives.
However, despite passing through the termios settings I get this error:
bash: cannot set terminal process group (8751): Inappropriate ioctl for device
bash: no job control in this shell
This is my code any help is much appreciated.
N.B. I am aware that I haven't implemented SIGNAL handling
#define _XOPEN_SOURCE 700
#include <stdlib.h>
#include <stdio.h>
#include <unistd.h>
#include <sys/poll.h>
#include <pty.h>
#include "libtmt/tmt.h"
#include <ncurses.h>
typedef struct App {
int pty_fd;
pid_t pid;
} App;
App *App_new(char **argv) {
App *self = malloc(sizeof(App));
int slave_pty_fd, master_pty_fd;
struct termios terminal_settings;
tcgetattr(STDERR_FILENO, &terminal_settings);
struct winsize terminal_size = {
.ws_row = 24,
.ws_col = 80,
};
int ret = openpty(&master_pty_fd, &slave_pty_fd, NULL, &terminal_settings, &terminal_size);
if (ret < 0) {
perror("openpty");
exit(1);
}
self->pty_fd = master_pty_fd;
self->pid = fork();
if (self->pid < 0) {
perror("fork");
exit(1);
}
if (self->pid == 0) {
close(master_pty_fd);
if (dup2(slave_pty_fd, STDIN_FILENO) != STDIN_FILENO) {
perror("dup2");
exit(1);
}
if (dup2(slave_pty_fd, STDOUT_FILENO) != STDOUT_FILENO) {
perror("dup2");
exit(1);
}
if (dup2(slave_pty_fd, STDERR_FILENO) != STDERR_FILENO) {
perror("dup2");
exit(1);
}
if (execvp(argv[0], argv) < 0) {
perror("execvp");
exit(1);
}
}
close(slave_pty_fd);
return self;
}
int main() {
int ret;
char *argv[] = {
"/bin/bash",
NULL,
};
App *app = App_new(argv);
while (TRUE) {
struct pollfd fds[2] = {
{ .fd = app->pty_fd, .events = POLLIN },
{ .fd = STDIN_FILENO, .events = POLLIN },
};
ret = poll(fds, 2, -1);
if (ret < 0) {
perror("poll");
exit(1);
}
if (fds[0].revents & POLLIN) {
char buf[1024];
ret = read(app->pty_fd, buf, sizeof(buf));
if (ret < 0) {
perror("read");
exit(1);
}
if (ret == 0) {
printf("0 read but poll said it was okay\n");
exit(0);
}
write(STDOUT_FILENO, buf, ret);
}
if (fds[1].revents & POLLIN) {
char buf[1024];
ret = read(STDIN_FILENO, buf, sizeof(buf));
if (ret < 0) {
perror("read");
exit(1);
}
if (ret == 0) {
printf("0 read but poll said it was okay\n");
exit(0);
}
write(app->pty_fd, buf, ret);
}
}
}
You need to run a program from withing attached terminal. See What does the sh:cannot set terminal process group (-1) inappropriate ioctl for device error mean?
You can verify if there is any current active TTY you can attach to:
# tty
/dev/pty0

PseudoTerminal C - How To

I am currently trying to make an application that will receive information from a client and send it to be executed in a server. For that I need to use PseudoTerminals.
I followed the example from a book and I ended up with this code
#include <stdlib.h>
#include <fcntl.h>
#include <errno.h>
#include <unistd.h>
#include <string.h>
#include <stdio.h>
#include <sys/ioctl.h>
#include <sys/stat.h>
int ptyMasterOpen(char *slavName, size_t snLen)
{
int masterFd, savedErrno;
char *p;
masterFd = posix_openpt(O_RDWR | O_NOCTTY);
printf("Master: %d \n", masterFd);
if(masterFd == -1)
return -1;
if(grantpt(masterFd) == -1 || unlockpt(masterFd) == -1)
{
savedErrno = errno;
close(masterFd);
errno = savedErrno;
return -1;
}
p = ptsname(masterFd); /*Get the name of the of the slave*/
if(p == NULL)
{
savedErrno = errno;
close(masterFd);
errno = savedErrno;
return -1;
}
printf("Slave: %s \n", p);
//*
if(strlen(p) < snLen)
{
strncpy(slavName, p, snLen);
}
else
{
close(masterFd);
errno = EOVERFLOW;
return -1;
}
//*/
return masterFd;
}
pid_t ptyFork(int *masterFd, char *slavName, size_t snLen)
{
int mfd, slaveFd, saveErrno;
pid_t childPid;
char slname[MAX_SNAME];
char cIn[100], cOut[100];
int out = -1, in = -1;
mfd = ptyMasterOpen(slname, MAX_SNAME);
if(mfd == -1)
return -1;
if(slavName != NULL)
{
if(strlen(slname) < snLen)
{
strncpy(slavName, slname, snLen);
}
else
{
close(mfd);
errno = EOVERFLOW;
return -1;
}
}
childPid = fork();
if(childPid == -1)
{
saveErrno = errno;
close(mfd);
errno = saveErrno;
return -1;
}
if(childPid != 0)
{
*masterFd = mfd;
return childPid;
}
close(mfd);
slaveFd = open(slname, O_RDWR);
if(slaveFd != -1)
{
sprintf(cOut, "/tmp/out%d", slaveFd);
sprintf(cIn, "/tmp/in%d", slaveFd);
mkfifo(cOut, S_IRUSR|S_IWUSR);
out = open(cOut, O_RDWR|O_TRUNC|O_NONBLOCK);
mkfifo(cIn, S_IRUSR|S_IWUSR);
in = open(cIn, O_RDONLY|O_TRUNC);dup2(out, STDERR_FILENO);
dup2(out, STDOUT_FILENO);
dup2(in, STDIN_FILENO);
}
else
{
printf("Problem with slave\n\r");
fflush(stdout);
}
//*
if(dup2(slaveFd, STDIN_FILENO) != STDIN_FILENO || dup2(slaveFd, STDERR_FILENO) != STDERR_FILENO || dup2(slaveFd, STDOUT_FILENO) != STDOUT_FILENO)
{
printf("Error on duplicating Files");
close(slaveFd);
exit(0);
}
else
{
dup2(out, STDERR_FILENO);
dup2(out, STDOUT_FILENO);
dup2(in, STDIN_FILENO);
}
//*/
return slaveFd;
}
The problem is:
sprintf(cOut, "/tmp/out%d", childPid);
sprintf(cIn, "/tmp/in%d", childPid);
always return 0 even when I print them in main and they are values like 952...
also using echo "ls" > "/tmp/inxx" and cat /tmp/outxx does nothing.
I believe the problem is when the fork is done, the variables lose their values or something, because, it prints the error messages now, without the while(1) on main
int main(int argc, const char * argv[])
{
// insert code here...
int masterFd;
pid_t slaveFd;
char slavName[MAX_SNAME];
slaveFd = ptyFork(&masterFd, slavName, MAX_SNAME);
//close(masterFd);
//while(1);
return 0;
}
Can anyone help?
Thanks

Named pipe block child process that uses pipe in C

The child_filter has to read values from pipefd and write these in a named pipe.
The problem is that if i try to un-comment the comment[3] (the open of the named-pipe) the function won't print values, it seem to be stuck on read() call. Instead, if i do not open the fifo pipe it works.
I need named pipe for other stuffs.
What shall i modify? Maybe pipe and named-pipe conflicts using them together?
Thanks.
#include<stdlib.h>
#include<stdio.h>
#include<string.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <sys/stat.h>
#include <fcntl.h>
#define FIFONAME "./my-fgrep-named-pipe"
typedef struct{
int i;
int v;
int word;
int filename;
char word_string[250];
char filename_string[250];
}parameters;
int pipefd[2];
void child_reader(parameters params){
FILE* fp;
char *line = NULL;
size_t len = 0;
ssize_t read;
if(params.filename==0)
fp = stdin;
else
fp = fopen(params.filename_string, "r");
close(pipefd[0]); /* Close unused read end */
if (fp != NULL){
while ((read = getline(&line, &len, fp)) != -1) {
//printf("Retrieved line of length %zu :\n", read);
//printf("%s", line);
write(pipefd[1], line, strlen(line));
}
fclose(fp);
}
free(line);
printf("child reader > end\n");
exit(0);
}
void child_filter(parameters params){
char c;
char temp[250];
int i=0;
char *temp2;
int fifofd;
close(pipefd[1]); /* Close unused write pipe end */
printf("read from pipe\n");
if( (fifofd = open(FIFONAME, O_WRONLY)) == -1) printf("Error WW\n");
while (read(pipefd[0], &c, 1) > 0){
if (c == '\n' || c == '\r'){
temp[i] = '\n';
if(i>0){
temp2=strtok(temp, "\n");
//temp2[i] = '\n';
// printf("[%s]\n", temp2);
write(fifofd, temp2, strlen(temp2));
}i=0;
}
else{
temp[i] = c;
i++;
}
}
close(fifofd);
printf("child filter > end\n");
exit(0);
}
void child_writer(parameters params){
char c;
int fifofd;
char temp[250];
int i=0;
char *temp2;
if( (fifofd = open(FIFONAME, O_RDONLY)) == -1) printf("Error RR\n");
while (read(fifofd, &c, 1) > 0){
printf("entry > [%c] \n", c);
}
printf("exit-------------\n");
close(fifofd);
unlink(FIFONAME);
exit(0);
}
int main(int argc, char *argv[]){
char* temp1;
parameters params;
int forkResult;
params.i=0;
params.v=0;
params.word=0;
params.filename=0;
int pid_r, pid_w, pid_f;
if(argc<2){
printf("error\n");
exit(0);
}
if(strcmp(argv[1],"-i") == 0)
params.i++;
if(strcmp(argv[1],"-v") == 0)
params.v++;
if(argc>2){
if(strcmp(argv[2],"-i") == 0)
params.i++;
if(strcmp(argv[2],"-v") == 0)
params.v++;
}
if(params.i == 0 && params.v == 0){
params.word++;
strcpy(params.word_string, argv[1]);
if(argc>2){
params.filename++;
strcpy(params.filename_string, argv[2]);
}
}
else if(params.i != 0 && params.v != 0){
if(argc>3){
params.word++;
strcpy(params.word_string, argv[3]);
}
if(argc>4){
params.filename++;
strcpy(params.filename_string, argv[4]);
}
}
else{
if(argc>2){
params.word++;
strcpy(params.word_string, argv[2]);
}
if(argc>3){
params.filename++;
strcpy(params.filename_string, argv[3]);
}
}
printf("Result: i[%d], v[%d], name[%d], filename[%d]\n", params.i, params.v, params.word, params.filename);
if(params.word==0){
printf("Error X\n");
exit(0);
}
if (pipe(pipefd) == -1) {
printf("pipe error\n");
exit(0);
}
unlink(FIFONAME);
if( mkfifo(FIFONAME, 0666) != 0) printf("Error fifo1\n");
if( (pid_r=fork()) == 0 ){
child_reader(params);
}
if( (pid_f=fork()) == 0 ){
child_filter(params);
}
if( (pid_w=fork()) == 0 ){
child_writer(params);
}
waitpid(pid_r, NULL, 0);
printf("Reader finished\n");
close(pipefd[1]);
waitpid(pid_f, NULL, 0);
close(pipefd[0]);
printf("filter finished\n");
waitpid(pid_w, NULL, 0);
printf("Done!\n");
exit(0);
}
If you open a named pipe for writing then it'll block until the other end is opened for reading. That's an expected behaviour.
I need named pipe for other stuffs
Well, if there's no one reading from the pipe then what other stuff can you do with the write end of the pipe? So, you have to ensure there's a reader from the pipe or delay opening the pipe until there's someone ready to read from it. One other option is to open with O_RDWR.
The problem was that forks dupe file descriptors and so they were still opened.
Due to this reason, child process won't finish.
Fixed code:
#include<stdlib.h>
#include<stdio.h>
#include<string.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <sys/stat.h>
#include <fcntl.h>
#define FIFONAME "./my-fgrep-named-pipe"
typedef struct{
int i;
int v;
int word;
int filename;
char word_string[250];
char filename_string[250];
}parameters;
int pipefd[2];
void child_reader(parameters params){
FILE* fp;
char *line = NULL;
size_t len = 0;
ssize_t read;
if(params.filename==0)
fp = stdin;
else
fp = fopen(params.filename_string, "r");
close(pipefd[0]); /* Close unused read end */
if (fp != NULL){
while ((read = getline(&line, &len, fp)) != -1) {
//printf("Retrieved line of length %zu :\n", read);
//printf("%s", line);
write(pipefd[1], line, strlen(line));
}
fclose(fp);
}
free(line);
close(pipefd[1]); /* Close unused read end */
printf("child reader > done\n");
exit(0);
}
void child_filter(parameters params){
char c;
char temp[250];
int i=0;
char *temp2;
int fifofd;
close(pipefd[1]); /* Close unused write pipe end */
if( (fifofd = open(FIFONAME, O_WRONLY)) == -1) printf("Error fifoWW\n");
printf("read from pipe\n");
while (read(pipefd[0], &c, 1) > 0){
if (c == '\n' || c == '\r'){
temp[i] = '\n';
if(i>0){
temp2=strtok(temp, "\n");
//temp2[i] = '\n';
//printf("[%s]\n", temp2);
write(fifofd, temp2, strlen(temp2)); //prima senza +1;
}i=0;
}
else{
temp[i] = c;
i++;
}
}
close(fifofd);
close(pipefd[0]);
printf("child filter > done\n");
exit(0);
}
void child_writer(parameters params){
char c;
char temp[250];
int i=0;
char *temp2;
int size;
int fifofd;
if( (fifofd = open(FIFONAME, O_RDONLY)) == -1) printf("Error fifoRR\n");
do{
printf("entry> [%c] \n", c);
size = read(fifofd, &c, 1);
printf("next size read> %d\n", size);
}while(size > 0);
close(fifofd);
printf("exit-------------\n");
//unlink(FIFONAME);
exit(0);
}
int main(int argc, char *argv[]){
char* temp1;
parameters params;
int esitoFork;
params.i=0;
params.v=0;
params.word=0;
params.filename=0;
int pid_r, pid_w, pid_f;
FILE *myfifo;
if(argc<2){
printf("error \n");
exit(0);
}
if(strcmp(argv[1],"-i") == 0)
params.i++;
if(strcmp(argv[1],"-v") == 0)
params.v++;
if(argc>2){
if(strcmp(argv[2],"-i") == 0)
params.i++;
if(strcmp(argv[2],"-v") == 0)
params.v++;
}
if(params.i == 0 && params.v == 0){ // [3] ho il nome, [4] ho il filename
params.word++;
strcpy(params.word_string, argv[1]);
if(argc>2){
params.filename++;
strcpy(params.filename_string, argv[2]);
}
}
else if(params.i != 0 && params.v != 0){ // [2] ho il nome, [3] ho il filename
if(argc>3){
params.word++;
strcpy(params.word_string, argv[3]);
}
if(argc>4){
params.filename++;
strcpy(params.filename_string, argv[4]);
}
}
else{ // [3] ho il nome, [4] ho il filename
if(argc>2){
params.word++;
strcpy(params.word_string, argv[2]);
}
if(argc>3){
params.filename++;
strcpy(params.filename_string, argv[3]);
}
}
printf("Result: i[%d], v[%d], nome[%d], filename[%d]\n", params.i, params.v, params.word, params.filename);
if(params.word==0){
printf("Error syntax\n");
exit(0);
}
if (pipe(pipefd) == -1) {
printf("pipe error\n");
exit(0);
}
if( mkfifo(FIFONAME, 0666) != 0) printf("Error fifo\n");
if( (pid_r=fork()) == 0 ){
child_reader(params);
}
if( (pid_f=fork()) == 0 ){
child_filter(params);
}
close(pipefd[0]);
close(pipefd[1]);
if( (pid_w=fork()) == 0 ){
child_writer(params);
}
waitpid(pid_r, NULL, 0);
printf("Reader finished\n");
waitpid(pid_f, NULL, 0);
printf("filter finished\n");
waitpid(pid_w, NULL, 0);
printf("Done!\n");
unlink(FIFONAME);
exit(0);
}

Unix shell's input redirection not working

I found the same question but there was no answer.
In building my own unix shell, my output redirection is working fine, but when I try the input it does not do anything. If you could help me figure out the problem that would be great.
This is my exec function code:
void execute (char **args)
{
int pid, status;
pid = fork ();
if (pid < 0)
{
perror ("Error forking!");
return;
}
else if (pid > 0)
{
fflush(0);
while (wait (&status) != pid)
continue;
}
else if (pid == 0)
{
int i,in=0,out=0;
char input[BUF_SIZE],output[BUF_SIZE];
for(i=0;args[i]!=NULL;i++)
{
if(strcmp(args[i],"<")==0)
{
args[i]=NULL;
strcpy(input,args[i+1]);
in=2;
}
if(strcmp(args[i],">")==0)
{
args[i]=NULL;
strcpy(output,args[i+1]);
out=2;
}
}
if(in)
{
int fd0;
if ((fd0 = open(input, O_RDONLY, 0)) < 0)
{
perror("Couldn't open input file");
exit(0);
}
dup2(fd0, 0);
close(fd0);
}
if (out)
{
int fd1;
if ((fd1 = creat(output , 0644)) < 0)
{
perror("Couldn't open the output file");
exit(0);
}
dup2(fd1, 1);
close(fd1);
}
execvp (*args, args);
perror("execvp");
_exit(1);
}
Here is my whole code:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <signal.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <unistd.h>
#include <sys/stat.h>
#include <fcntl.h>
#define ARGSIZE 20
#define BUF_SIZE 1024
void execute (char **args);
void cd (char *directory);
int killpid (char *pitstr, int sig);
int main (void)
{
char line[BUF_SIZE] = {0};
char *args[ARGSIZE] = {NULL};
char *token;
int i, argIndex = 0;
while (1)
{
argIndex = 0;
for (i = 0; i < ARGSIZE; i++)
args[i] = NULL;
printf ("shell> ");
if (fgets (line, BUF_SIZE, stdin) == NULL)
{
printf ("EOF received\n");
return 0;
}
if (*line == '\n')
continue;
token = strtok (line, " \n");
while (token != NULL)
{
args[argIndex] = token;
token = strtok (NULL, " \n");
argIndex++;
}
if (!argIndex)
continue;
if (strcmp (args[0], "quit") == 0 || strcmp (args[0], "exit") == 0)
break;
if ((strcmp (args[0], "cd") == 0))
cd (args[1]);
else if ((strcmp (args[0], "kill") == 0))
{
if (args[1])
killpid (args[1], SIGTERM);
}
else
execute (args);
}
return 0;
}
void execute (char **args)
{
int pid, status;
pid = fork ();
if (pid < 0)
{
perror ("Error forking!");
return;
}
else if (pid > 0)
{
fflush(0);
while (wait (&status) != pid)
continue;
}
else if (pid == 0)
{
int i,in=0,out=0;
char input[BUF_SIZE],output[BUF_SIZE];
for(i=0;args[i]!=NULL;i++)
{
if(strcmp(args[i],"<")==0)
{
args[i]=NULL;
strcpy(input,args[i+1]);
in=2;
}
if(strcmp(args[i],">")==0)
{
args[i]=NULL;
strcpy(output,args[i+1]);
out=2;
}
}
if(in)
{
int fd0;
if ((fd0 = open(input, O_RDONLY, 0)) < 0)
{
perror("Couldn't open input file");
exit(0);
}
dup2(fd0, 0);
close(fd0);
}
if (out)
{
int fd1;
if ((fd1 = creat(output , 0644)) < 0)
{
perror("Couldn't open the output file");
exit(0);
}
dup2(fd1, 1);
close(fd1);
}
execvp (*args, args);
perror("execvp");
_exit(1);
}
}
void cd (char *directory)
{
char dir[BUF_SIZE] = {0};
if (!directory)
{
directory = getenv ("HOME");
if (chdir (directory))
fprintf (stderr, "Failed to enter directory: %s\n", directory);
else
printf ("%s\n", directory);
return;
}
if (*directory == '~')
{
strcpy (dir, getenv ("HOME"));
strcat (dir, "/");
strcat (dir, directory + 2);
if (chdir (dir))
fprintf (stderr, "Failed to enter directory: %s\n", dir);
else
printf ("%s\n", dir);
return;
}
if (chdir (directory))
fprintf (stderr, "Failed to enter directory: %s\n", directory);
else
printf ("%s\n", directory);
}
int killpid (char *pidstr, int sig)
{
pid_t pid = (pid_t)atoi (pidstr);
if (pid < 1)
{
fprintf (stderr, "warning: requested pid < 1, ignoring\n");
return (int)pid;
}
printf (" killing pid '%d' with signal '%d'\n", (int)pid, sig);
return 0;
}
When you see a < in the args array here
if(strcmp(args[i],"<")==0)
you set args[i] to NULL
args[i]=NULL;
But then, you pass it to strcmp()
if(strcmp(args[i],">")==0)
and your child process will happily segfault. Use an if-else-construct here:
if(strcmp(args[i],"<")==0) {
args[i]=NULL;
strcpy(input,args[i+1]);
in=2;
} else if(strcmp(args[i],">")==0) {
args[i]=NULL;
strcpy(output,args[i+1]);
out=2;
}
This should fix the error.
Furthermore, this might come in handy to detect such situations:
...
while (wait (&status) != pid)
continue;
if (WIFSIGNALED(status))
printf("Killed by signal %d%s\n",
WTERMSIG(status), WCOREDUMP(status)?" (Core dumped)":"");

How to send broadcast messages with named pipe using C?

I want to write a program with 1 sender and 3 receivers. The sender can send individual message to each receivers and group message to all receivers. I am using named pipes to achieve this but can't send group message to all receivers synchronously. Any idea to send broadcast message with named pipe?
Sender program:
/* Sender */
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <fcntl.h>
int main()
{
char pipename1[] = "/tmp/pipe1";
char pipename2[] = "/tmp/pipe2";
char pipename3[] = "/tmp/pipe3";
char pipename4[] = "/tmp/pipe4";
char buf1[80];
char buf2[80];
char buf3[80];
char buf4[80];
int fd1, fd2, fd3, fd4;
int select1, select2;
int n,pid;
/* Pipe Creation */
if (access(pipename1, F_OK) == -1) {
fd1 = mkfifo(pipename1, 0700);
if (fd1 != 0) {
printf("Pipe creation error\n");
exit(1);
}
}
if (access(pipename2, F_OK) == -1) {
fd2 = mkfifo(pipename2, 0700);
if (fd2 != 0) {
printf("Pipe creation error\n");
exit(1);
}
}
if (access(pipename3, F_OK) == -1) {
fd3 = mkfifo(pipename3, 0700);
if (fd3 != 0) {
printf("Pipe creation error\n");
exit(1);
}
}
if (access(pipename4, F_OK) == -1) {
fd4 = mkfifo(pipename4, 0700);
if (fd4 != 0) {
printf("Pipe creation error\n");
exit(1);
}
}
pid = fork();
if (pid < 0) {
printf("Fork failed\n");
exit(1);
} else if (pid == 0) {
printf("1. Send individual message\n");
printf("2. Send group message\n");
printf("Please select an option: ");
scanf("%d", &select1);
switch(select1) {
case 1:
printf("1. Receiver 1 (Mary)\n");
printf("2. Receiver 2 (John)\n");
printf("3. Receiver 3 (Peter)\n");
printf("Please select a receiver: ");
scanf("%d", &select2);
switch(select2) {
case 1:
/* Open pipe for writing */
if ((fd1 = open(pipename1, O_WRONLY)) < 0) {
printf("Pipe open error\n");
exit(1);
}
while (1) {
printf("Send message to Mary: \n");
n = read(STDIN_FILENO,buf1,80);
if (n <= 0) break;
buf1[--n] = 0;
printf("Sending message [%s] to Mary\n",buf1);
write(fd1,buf1,n);
}
close(fd1);
break;
case 2:
/* Open pipe for writing */
if ((fd2 = open(pipename2, O_WRONLY)) < 0) {
printf("Pipe open error\n");
exit(1);
}
while (1) {
printf("Send message to John: \n");
n = read(STDIN_FILENO,buf2,80);
if (n <= 0) break;
buf2[--n] = 0;
printf("Sending message [%s] to John\n",buf2);
write(fd2,buf2,n);
}
break;
case 3:
/* Open pipe for writing */
if ((fd3 = open(pipename3, O_WRONLY)) < 0) {
printf("Pipe open error\n");
exit(1);
}
while (1) {
printf("Send message to Peter: \n");
n = read(STDIN_FILENO,buf3,80);
if (n <= 0) break;
buf3[--n] = 0;
printf("Sending message [%s] to Peter\n",buf3);
write(fd3,buf3,n);
}
break;
default:
printf("Receiver not found\n");
break;
}
case 2:
/* Open pipe for writing */
if ((fd4 = open(pipename4, O_WRONLY)) < 0) {
printf("Pipe open error\n");
exit(1);
}
while (1) {
printf("Send message to Group: \n");
n = read(STDIN_FILENO,buf4,80);
if (n <= 0) break;
buf4[--n] = 0;
printf("Sending message [%s] to Group\n",buf4);
write(fd4,buf4,n);
}
break;
default:
printf("Wrong Input!\n");
break;
}
} else {
wait(NULL);
}
unlink(pipename1);
unlink(pipename2);
unlink(pipename3);
unlink(pipename4);
exit(0);
}
Receiver1 program:
/* Receiver1 */
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <fcntl.h>
int main()
{
char pipename1[] = "/tmp/pipe1";
char pipename4[] = "/tmp/pipe4";
char buf1[80];
char buf4[80];
int fd1, fd4;
int n, pid;
printf("Mary is online\n");
pid = fork();
if (pid < 0) {
printf("Fork failed\n");
exit(1);
} else if (pid == 0) {
/* Open pipe for reading */
if ((fd1 = open(pipename1, O_RDONLY)) < 0) {
printf("Pipe open error\n");
exit(1);
}
while ((n = read(fd1, buf1, 80)) > 0) {
buf1[n] = 0;
printf("[Message received:] %s\n", buf1, n);
}
close(fd1);
exit(0);
} else {
/* Open pipe for reading */
if ((fd4 = open(pipename4, O_RDONLY)) < 0) {
printf("Pipe open error\n");
exit(1);
}
while ((n = read(fd4, buf4, 80)) > 0) {
buf4[n] = 0;
printf("[Message received:] %s\n", buf4, n);
}
close(fd4);
wait(NULL);
exit(0);
}
}
Receiver2 program:
/* Receiver2 */
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <fcntl.h>
int main()
{
char pipename2[] = "/tmp/pipe2";
char pipename4[] = "/tmp/pipe4";
char buf2[80];
char buf4[80];
int fd2, fd4;
int n, pid;
printf("John is online\n");
pid = fork();
if (pid < 0) {
printf("Fork failed\n");
exit(1);
} else if (pid == 0) {
/* Open pipe for reading */
if ((fd2 = open(pipename2, O_RDONLY)) < 0) {
printf("Pipe open error\n");
exit(1);
}
while ((n = read(fd2, buf2, 80)) > 0) {
buf2[n] = 0;
printf("[Message received:] %s\n", buf2, n);
}
close(fd2);
exit(0);
} else {
/* Open pipe for reading */
if ((fd4 = open(pipename4, O_RDONLY)) < 0) {
printf("Pipe open error\n");
exit(1);
}
while ((n = read(fd4, buf4, 80)) > 0) {
buf4[n] = 0;
printf("[Message received:] %s\n", buf4, n);
}
close(fd4);
wait(NULL);
exit(0);
}
}
Receiver3 program:
/* Receiver3 */
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <fcntl.h>
int main()
{
char pipename3[] = "/tmp/pipe3";
char pipename4[] = "/tmp/pipe4";
char buf3[80];
char buf4[80];
int fd3, fd4;
int n, pid;
printf("Peter is online\n");
pid = fork();
if (pid < 0) {
printf("Fork failed\n");
exit(1);
} else if (pid == 0) {
/* Open pipe for reading */
if ((fd3 = open(pipename3, O_RDONLY)) < 0) {
printf("Pipe open error\n");
exit(1);
}
while ((n = read(fd3, buf3, 80)) > 0) {
buf3[n] = 0;
printf("[Message received:] %s\n", buf3, n);
}
close(fd3);
exit(0);
} else {
/* Open pipe for reading */
if ((fd6 = open(pipename4, O_RDONLY)) < 0) {
printf("Pipe open error\n");
exit(1);
}
while ((n = read(fd4, buf4, 80)) > 0) {
buf4[n] = 0;
printf("[Message received:] %s\n", buf4, n);
}
close(fd4);
wait(NULL);
exit(0);
}
}

Resources