Read from stdin and "encrypt" the input in a child process - c

I have to write a little C program that does the following:
read from stdin
create a child process using fork and encrypt the input with crypt in that child process
use sleep with some random time to simulate the encrypting process and the asynchronous work of the child processes
in my parent process I should catch all the exit-codes of my child processes (using the singal SIGCHLD)
if the user presses Ctrl+C my program should wait for all child processes to finish, then terminate
if the user presses Ctrl+D, I should "ignore" that and read again from stdin
I'm reading from stdin using fgets and I also should catch the EINTR error (I think that's the Ctrl+D "signal"?)
Here is my code so far:
#include "stdio.h"
#include "stdlib.h"
#include "string.h"
#include "unistd.h"
#include "crypt.h"
#include "signal.h"
#include "errno.h"
#include "sys/wait.h"
char * encryptWord(char* word);
void childTerminated(int sig);
void terminateAllAndExit(int sig);
void nop(int sig);
void readFromStdin();
int childPIDs[1024];
int childProcesses = 0;
int main(int argc, char ** argv) {
readFromStdin();
}
void readFromStdin(void) {
char buffer[1024];
int pid;
while(fgets(buffer, 1024, stdin) != NULL) {
pid = fork();
if(pid == 0) {
signal(SIGINT, nop);
char * encrypted = encryptWord(buffer);
sleep(rand() % 10);
printf("ecnr: %s -> %s\n", buffer, encrypted);
exit(EXIT_SUCCESS);
}
else if(pid > 0) {
signal(SIGCHLD, childTerminated);
signal(SIGINT, terminateAllAndExit);
childPIDs[childProcesses] = pid;
childProcesses++;
}
}
//printf("childProcesses: %d", childProcesses);
}
char * encryptWord(char* word) {
// remove the \n at the end of the input
word[strlen(word)-1] = 0;
word = crypt(word,"sr");
return word;
}
void childTerminated(int sig) {
childProcesses--;
//printf("child terminated.\n");
}
void terminateAllAndExit(int sig) {
//pid_t p;
int status;
//printf("childProcesses: %d\n", childProcesses);
while(childProcesses > 0) {
(void)wait(&status);
if(WEXITSTATUS(status) == EXIT_SUCCESS) {
childProcesses--;
}
}
printf("All child processes terminated. Exiting...\n");
exit(EXIT_SUCCESS);
}
void nop(int sig) {
//signal(SIGINT, nop);
}
The code is working pretty nice now, encrypting works in my child processes and simulating the time they need to encrypt the input.
But, if I press Ctrl+C it's not working how it should. All child processes terminate immediately instead of waiting the time I've set in sleep.
And the last one, how can I catch the EINTR error?
Thank's for your help!

Related

How to supply input to a thread which is polling for stdin, form another thread in the same process?

Referring to following code example, I want the main thread to supply the number num that the child thread is expecting using scanf.
I tried this way to write the wordcount (9) to stdin which is to be read by child thread, but it is not working.
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <string.h>
#include <pthread.h>
void* child_thread_func(void* terminalflag)
{
int num=0;
printf("Trying to read num from stdin\n");
scanf("%d",&num);
/*expecting 9 to be printed here*/
printf("Entered number is %d\n", num);
}
int main () {
pthread_t tid;
if (pthread_create(&tid, NULL, &child_thread_func, NULL) != 0) {
printf("Failed to initialize thread\n");
exit(1);
}
sleep(2);
char buffer[50];
FILE *wfp = popen("wc -c", "w");
if (wfp != NULL) {
sprintf(buffer, "dummyword");
int save_stdin = dup(fileno(stdin));
dup2(fileno(wfp), fileno(stdin));
fwrite(buffer, sizeof(char), strlen(buffer), wfp);
dup2(save_stdin, fileno(stdin));
pclose(wfp);
}
pthread_join(tid, NULL);
}
Can someone suggest a correct way or any other alternative way to do this?
Thanks.
I don't think there is any good way for a process to write text to its own stdin; stdin is meant to be a way for the parent process (or the user, if the parent process is a Terminal window) to send data to your process, not for your process to send data to itself.
However, you could achieve a similar result by having your child thread use select() or similar to read input from both stdin and from the output end of a pipe; then your parent process can send data to the child process by writing to the input end of that same pipe.
Below is a modified version of your program demonstrating the technique. Note that the child thread will print out any text that you type into stdin; and also the main thread will send a line of text to the child thread once every 5 seconds, and the child thread will also print out that text. After the main thread has sent 5 messages to the child thread, the main thread will close its end of the pipe, causing the child thread to exit and then the process can exit cleanly as well.
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <sys/select.h>
#include <string.h>
#include <pthread.h>
#include <unistd.h>
static int pipeReadFD = -1;
static int ReadTextFrom(const char * descriptionOfSender, int fd)
{
char buf[256];
const int numBytesRead = read(fd, buf, sizeof(buf)-1); // -1 so we always have room to place NUL terminator byte
if (numBytesRead > 0)
{
buf[numBytesRead] = '\0'; // make sure the string is NUL-terminated
printf("ReadTextFrom(): Read %i bytes from [%s]: [%s]\n", numBytesRead, descriptionOfSender, buf);
}
return numBytesRead;
}
void* init_on_sys_ready(void* terminalflag)
{
int num=0;
printf("Child thread: trying to read text from stdin\n");
while(1)
{
const int stdinFD = fileno(stdin);
const int maxFD = (pipeReadFD > stdinFD) ? pipeReadFD : stdinFD;
fd_set readFDSet;
FD_ZERO(&readFDSet);
FD_SET(stdinFD, &readFDSet);
FD_SET(pipeReadFD, &readFDSet);
const int selRet = select(maxFD+1, &readFDSet, NULL, NULL, NULL);
if (selRet >= 0)
{
if ((FD_ISSET(stdinFD, &readFDSet))&&(ReadTextFrom("stdin", stdinFD) <= 0)) break;
if ((FD_ISSET(pipeReadFD, &readFDSet))&&(ReadTextFrom("pipe", pipeReadFD) <= 0)) break;
}
else
{
perror("select");
break;
}
}
printf("Child thread exiting!\n");
return NULL;
}
int main(int argc, char ** argv)
{
int pipeFDs[2];
if (pipe(pipeFDs) < 0)
{
perror("pipe");
return -1;
}
pipeReadFD = pipeFDs[0];
int pipeWriteFD = pipeFDs[1];
pthread_t tid;
if (pthread_create(&tid, NULL, &init_on_sys_ready, NULL) != 0) {
printf("Failed to initialize CLI\n");
exit(1);
}
int count = 0;
for (int count=0; count < 5; count++)
{
char buf[512];
snprintf(buf, sizeof(buf), "Hello #%i from main thread", ++count);
const size_t slen = strlen(buf);
if (write(pipeWriteFD, buf, slen) == slen)
{
printf("main() sent [%s] to the child thread via the pipe.\n", buf);
}
else
{
perror("write");
break;
}
sleep(5);
}
close(pipeWriteFD); // this will cause the child thread to exit ASAP
pthread_join(tid, NULL);
return 0;
}
popen's man states:
[...] the command's standard output is the same as that of the process that called popen()
So you just need a way to redirect stdout to stdin.
Which is exactly what pipe is for. It links an output fd with an input fd.
As pipe creates new fds, we need to use dup2 to replace stdin and stdout, as you've already did in your example code. Threads share the same memory, so you don't have to worry about any child/parent differences in fds.
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <string.h>
#include <pthread.h>
void* child_thread_func(void* terminalflag)
{
int num=0;
printf("Trying to read num from stdin\n");
scanf("%d",&num);
/*expecting 9 to be printed here*/
printf("Entered number is %d\n", num);
}
int main () {
setbuf(stdin, NULL);
pthread_t tid;
if (pthread_create(&tid, NULL, &child_thread_func, NULL) != 0) {
printf("Failed to initialize thread\n");
exit(1);
}
int save_stdin = dup(STDIN_FILENO);
int save_stdout = dup(STDOUT_FILENO);
int tube[2];
pipe(tube);
dup2(tube[0], STDIN_FILENO);
dup2(tube[1], STDOUT_FILENO);
char buffer[50] = {0};
FILE *wfp = popen("wc -c", "w");
if (wfp != NULL) {
sprintf(buffer, "dummyword");
fwrite(buffer, sizeof(char), strlen(buffer), wfp);
pclose(wfp);
}
dup2(save_stdin, STDIN_FILENO);
dup2(save_stdout, STDOUT_FILENO);
pthread_join(tid, NULL);
}

how to immediately wake up the daemon by sending him a SIGUSR1 signal

I wrote a program deamon which copy files with one folder to another .I have to implement SIGUSR1 which immediately wake up the daemon by sending him a SIGUSR1 signal. I do not know what I did wrong ,I use command kill -SIGUSR1 ,maybe wrong command?.Somebody know what is wrong with this code ?I did not have any warning after compiled this program,but just nothing happend
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <sys/types.h>
#include <unistd.h>
#include <syslog.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <sys/mman.h>
#include <dirent.h>
#include <fcntl.h>
#include <signal.h>
#define _XOPEN_SOURCE ;
int recursion = 0; //1 if enabled, otherwise 0
int sleepTime = 300;
int fileLimit = 0;
int signaL = 0;
int exitSignal = 0;
int buffer = 1000;
//Returns 0 if arguments are correct otherwise returns 1
int readArguments(int number, char **argv, char *source, char *goal);
int checkFileType(struct stat file);
int copy(char *source, char *target, mode_t mask);
int copy_map(char *source, char *target, struct stat *Source);
void syncCopy(char *source, char *target);
void syncRemove(char *source, char *target);
void my_handler(int sig)
{
syslog(LOG_INFO, "Daemon received signal SIGUSR1\n");
signaL = 1;
}
void exitFunction(int sig)
{
syslog(LOG_INFO, "Daemon received signal SIGUSR2\n");
exitSignal = 1;
}
int main(int argc, char **argv)
{
//char tables for paths
char source[500], goal[500];
struct stat Source, Goal;
struct sigaction my_action, old_action;
//checking and reading arguments
if (readArguments(argc, argv, source, goal) == 1)
exit(-1);
//checking paths
//checking if argv[1] and argv[2] are existing paths
if (lstat(source, &Source) != 0 || lstat(goal, &Goal) != 0) //bad result
{
printf("One of the paths or both dont exist\n");
exit(-1);
}
if (checkFileType(Source) != 0)
{
printf("Source path is not path to folder");
exit(-1);
}
if (checkFileType(Goal) != 0)
{
printf("Goal path is not path to folder");
exit(-1);
}
//forking the parent process
pid_t pid;
// Fork off the parent process and create new
pid = fork();
//if failure
if (pid < 0)
{
exit(-1);
}
// if it is native process
else if (pid > 0)
{
return 0;
}
//if pid==0 then it is childs process
//now we have to umask in order to write to any files(for exmaple logs)
umask(0);
openlog("logFile", LOG_PID, LOG_DAEMON);
syslog(LOG_INFO, "Deamon has just started running\n");
pid_t sid = setsid();
if (sid < 0)
{
syslog(LOG_ERR, "Error with session opening\n");
exit(-1);
}
//SIGNAL SIGUSR1
my_action.sa_handler = my_handler;
sigfillset(&my_action.sa_mask);
my_action.sa_flags = 0;
if (sigaction(SIGUSR1, &my_action, &old_action) < 0)
{
syslog(LOG_ERR, "Error with the use of SIGUSR1 signal\n");
exit(-1);
}
//SIGNAL SIGUSR2 for exiting daemon
my_action.sa_handler = exitFunction;
sigfillset(&my_action.sa_mask);
my_action.sa_flags = 0;
if (sigaction(SIGUSR2, &my_action, &old_action) < 0)
{
syslog(LOG_ERR, "Error with the use of SIGUSR2 signal\n");
exit(-1);
}
while (!exitSignal)
{
sleep(sleepTime);
switch (signaL)
{
case 0:
syslog(LOG_INFO, "Demon started working after %ds\n", sleepTime);
break;
case 1:
{
syslog(LOG_INFO, "Demon started working after SIGUSR1 signal\n");
signaL = 0; //Need to reeset signaL
break;
}
}
syncCopy(source, goal);
syncRemove(source, goal);
syslog(LOG_INFO, "Demon has just gone to sleep");
}
//at the end of program we need to close log using
syslog(LOG_INFO, "Demon has stopped\n");
closelog();
return 0;
}
Use command as kill -10 <pid> for SIGUSR1 and kill -12 <pid> for SIGUSR2.
kill -l // command to know the signal number.
Also make variable signaL , exitSignal as volatile sig_atomic_t type.
WHY volatile?
when a global variable updated in signal handler is periodically checked in some other function for appropriate action, we should always declare them using the volatile attribute in order to prevent the compiler from performing optimizations that result in the variable being stored in a register. In worst case, updated value of variable(updated in handler context) won't be visible to function polling for the variable.
WHY sig_atomic_t?
Reading and writing global variables may involve more than one machine- language instruction, and a signal handler may interrupt the main program in the middle of such an instruction sequence. (We say that access to the variable is nonatomic.) For this reason, the C language standards and SUSv3 specify an integer data type, sig_atomic_t, for which reads and writes are guaranteed to be atomic. Thus, a global flag variable that is shared between the main program and a signal handler should be declared as follows:
volatile sig_atomic_t signaL;

Use IPC Mechanism of pipe to complete the program so the child and parent print the same output

So I recently had an exam in a class about operating systems and it had asked me to write a program using pipe(). This program was intended to send and receive data through the pipe so that regardless of which file was run, the output would be the same.
The output should be the following.
Hello (from child) 1
Hello (from parent)
Hello (from child) 2
The template code was given as follows. (I could not change this code, I was only to insert code to make it work). No creativity... I know.
#include <unistd.h>
#include <stdio.h>
#include <sys/stat.h>
#include <sys/wait.h>
#include <signal.h>
int main() {
pid_t pid;
char buf[32];
if ((pid = fork()) < 0) {
puts("Error");
} else if(pid == 0) { //child
fprintf(stdout, "Hello (from child) 1\n");
fprintf(stdout, "Hello (from child) 2\n");
fflush(stdout);
}
else {
fprintf(stdout, "Hello (from parent)\n");
}
}
After some time my conclusion was the following. But after executing nothing printed. (I couldn't test it because it was a paper exam but I tested it after). Also, I was under a time crunch so I know the mistakes are probably frequent.
I added the User Start and User End to show where I could change the code. Any help would be appreciated.
#include <unistd.h>
#include <stdio.h>
#include <sys/stat.h>
#include <sys/wait.h>
#include <signal.h>
int main() {
pid_t pid;
char buf[32];
// User Start
int fds[2];
pipe(fds);
close(1);
dup(fds[1]);
// User End
if ((pid = fork()) < 0) {
puts("Error");
} else if(pid == 0) { //child
// User Start
// User End
fprintf(stdout, "Hello (from child) 1\n");
// User Start
write(fds[1],"Hello (from child) 1\n",21);
read(fds[0],buf,21);
write(fds[1],"Hello (from child) 2\n",21);
// User End
fprintf(stdout, "Hello (from child) 2\n");
// User Start
// User End
}
else {
// User Start
read(fds[0],buf,21);
// User End
fprintf(stdout, "Hello (from parent)\n");
// User Start
write(fds[1],"Hello (from parent)\n",21);
read(fds[0],buf,21);
// User End
}
}
UPDATE
#include <pthread.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <stdint.h>
int main()
{
pid_t pid;
char buf[32];
int returnstatus1;
int fds[2];
returnstatus1 = pipe(fds);
printf("Return status = %d\n",returnstatus1); //check if pipe is created or not
if(returnstatus1 == -1)
{
printf("Pipe 1 could not be created\n");
return 1;
}
if((pid = fork()) < 0)
{
puts("ERROR");
}
//child
else if(pid == 0)
{
fprintf(stdout,"hello (from child) 1\n");
close(fds[0]);
write(fds[1],"hello (from child) 1\n",21);
close(fds[1]);
read(fds[0],buf,21);
fprintf(stdout,"hello (from child) 2\n");
close(fds[0]);
write(fds[1],"hello (from child) 2",21);
}
//parent
else
{
close(fds[1]);
read(fds[0],buf,21);
fprintf(stdout,"hello (from parent)\n");
close(fds[0]);
write(fds[1],"hello (from parent)\n",21);
close(fds[1]);
read(fds[0],buf,21);
}
return 0;
}
The use of pipes for synchronization is slightly unorthodox, but it's perfectly doable. You have to remember that reading from an empty pipe is blocking — it waits until something has written to it.
Since it's clearer that way, I'll show the parent first, not the child. Of course it doesn't matter in which order you put the if branches — you can adapt it to your exam's format, and I strongly encourage you to do so in order to get a hang of it.
With that in mind, we go ahead:
#include <stdio.h>
#include <unistd.h>
int main (void) {
pid_t pid;
char buf;
int parent_pipes[2];
int child_pipes[2];
pipe(child_pipes);
pipe(parent_pipes);
if ((pid = fork()) < 0)
puts("Error");
else if (pid) {
// parent first!
// wait for the child to write something into the pipe...
read(*child_pipes, &buf, 1);
// and now write to stdout, and tell the child that we're ready
fprintf(stdout, "Hello (from parent)\n");
fflush(stdout);
write(parent_pipes[1], "R", 1); // it doesn't matter what we write; we have to write anything
} else {
// and now the child
// output and flush...
fprintf(stdout, "Hello (from child) 1\n");
fflush(stdout);
// ...and tell the parent that we're ready
write(child_pipes[1], "R", 1); // write end of the pipe
// now wait!
read(*parent_pipes, &buf, 1); // read end of the pipe
fprintf(stdout, "Hello (from child) 2\n");
}
return 0;
}

C - WHILE Loop with fork() / pipe() inside

I have a problem where I must implement a key logger into a shell we have made in class. I am having trouble getting the flow of the program within a while loop to continue looping after a child process is created and it has ran execlp().
Here is a simple program I have made to work on the part I am having trouble with.. My main program, pipe.c, includes the parent/child process with a while loop that "should" continue getting an input from the user with fgets(), create a child process, use dup2(), write to stdout, then the child process invoke the receive.c executable which will get the input from stdin and display it..
/* file: pipe.c */
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/wait.h>
int main() {
int key_logger_on = 0;
int p[2];
pid_t pid;
char str[256];
char input[1024];
int status;
char * file = "test.txt";
printf("Input :: ");
while(fgets(input, sizeof(input), stdin)) {
if (pipe(p)==-1) {
perror("Pipe create error");
exit(1);
}
if ((pid=fork())==-1) {
perror("Fork create error");
exit(1);
}
if (pid==0) {
close(p[1]); // Close write
dup2(p[0],0);
close(p[0]);
execlp("receive",file,NULL);
}
else {
close(p[0]); // Close read
fflush(stdout);
dup2(p[1],1);
close(p[1]);
write(1, input, strlen(input)+1);
waitpid(pid, NULL, 0);
}
printf("Input :: ");
}
}
Here is the simple receive.c that gets the stdin of the input and displays it. The file is just a test of passing a parameter.
/* file: receive.c */
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
int main(int argc, char *argv[]) {
char input[256];
fgets(input, sizeof(input), stdin);
printf("FILE: %s RECEIVE: %s", argv[0],input);
return 0;
}
Right now, all this does for me is when ran the first time, it gets the input, sends it to stdout, child calls receive, prints out the input, and then the whole parent program exits, the while loop is ignored, everything just ends. I'm very new to forks and pipes so this is very frustrating to deal with! Even made me post a question on here for the first time! Thank you very much in advance.
Did it today as repetition task for me . CHeck this code . I tested it with your receive too :
#define PREAD 0
#define PWRITE 1
/*
*
*/
int main(int argc, char** argv) {
int key_logger_on = 0;
int pIn[2];
int pOut[2];
pid_t pid;
char str[256];
char input[1024] = "";
int status;
char file[] = "test.txt";
char buf;
printf("Input :: ");
while (fgets(input,sizeof(input),stdin)) {
char nChar;
int nResult;
if (pipe(pIn) < 0) {
perror("allocating pipe for child input redirect");
return -1;
}
if (pipe(pOut) < 0) {
close(pIn[PREAD]);
close(pIn[PWRITE]);
perror("allocating pipe for child output redirect");
return -1;
}
pid = fork();
if ( pid==0) {
// child continues here
// redirect stdin
if (dup2(pIn[PREAD], 0) == -1) {
perror("stdin");
return -1;
}
// redirect stdout
if (dup2(pOut[PWRITE], 1) == -1) {
perror("stdout");
return -1;
}
// redirect stderr
if (dup2(pOut[PWRITE], 2) == -1) {
perror("stderr");
return -1;
}
// all these are for use by parent only
close(pIn[PREAD]);
close(pIn[PWRITE]);
close(pOut[PREAD]);
close(pOut[PWRITE]);
// run child process image
nResult = execl("receive",file,NULL);
exit(nResult);
} else if (pid > 0) {
// parent continues here
// close unused file descriptors, these are for child only
close(pIn[PREAD]);
close(pOut[PWRITE]);
write(pIn[PWRITE], input, strlen(input));
// char by char reading
while (read(pOut[PREAD], &nChar, 1) == 1) {
write(STDOUT_FILENO, &nChar, 1);
}
// close we done
close(pIn[PWRITE]);
close(pOut[PREAD]);
}
printf("Input :: ");
}
}

Signal sent to both child and parent process

As far as I understand signals sent to a parent process should not be sent to children. So why does SIGINT reach both the child and the parent in the example below?
#include <stdio.h>
#include <signal.h>
#include <stdlib.h>
#include <unistd.h>
void sigCatcher( int );
int main ( void ) {
if (signal(SIGINT, sigCatcher) == SIG_ERR) {
fprintf(stderr, "Couldn't register signal handler\n");
exit(1);
}
if(fork() == 0) {
char *argv[] = {"find","/",".",NULL};
execvp("find",argv);
}
for (;;) {
sleep(10);
write(STDOUT_FILENO, "W\n",3);
}
return 0;
}
void sigCatcher( int theSignal ) {
write(STDOUT_FILENO, "C\n",3);
}
If you are sending SIGINT by typing ^-C, the signal is sent to all processes in the foreground processing group. If you use kill -2, it will only go to the parent (or whichever process you indicate.)

Resources