Attach process to new Terminal (Mac OS) - c

I write a program, which should create new process (I use fork(), and next in child process call execl()) and communicate with it. Here is my server:
#include <sys/types.h>
#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <pthread.h>
int main(int argc, char *argv[]) {
pid_t process;
process = fork();
if (process == 0) {
printf("The program will be executed %s...\n\n", argv[0]);
printf("Executing %s", argv[0]);
execl("hello", "Hello, World!", NULL);
return EXIT_SUCCESS;
}
else if (process < 0) {
fprintf (stderr, "Fork failed.\n");
return EXIT_FAILURE;
}
waitpid(process, NULL, NULL);
return 0;
}
And here is my client:
#include <stdio.h>
int main(int argc, char *argv[])
{
int i=0;
printf("%s\n",argv[0]);
printf("The program was executed and got a string : ");
while(argv[++i] != NULL)
printf("%s ",argv[i]);
return 0;
}
The problem is the next: my client and server show output in the same terminal. I want them to show output in separate terminals. So, how can I do it?

You need to have two open terminals. The idea is to run your program in the first terminal and see the output of the client in the second terminal.
First, you need to know what is the ID of the second terminal. So in the second terminal do:
$ tty
/dev/pts/1
(note your output will be probably different because mine is a SSH connection and hence pts, yours will be /dev/tty)
And then in your child process, you tell it to use this other terminal for its output. Like this:
#include <stdio.h>
#include <fcntl.h>
int main(int argc, char *argv[]) {
int fd = open("/dev/pts/1",O_RDWR) ; // note that in your case you need to update this based on your terminal name
// duplicate the fd and overwrite the stdout value
if (fd < 0){
perror("could not open fd");
exit(0);
}
if (dup2(fd, 0) < 0 ){
perror("dup2 on stdin failed");
exit(0);
}
if (dup2(fd, 1) < 0 ){
perror("dup2 on stdout failed");
exit(0);
}
// from now on all your outputs are directed to the other terminal.
// and inputs are also come from other terminal.
}

Related

Named pipe (FIFO) halts execution when read and write are called

Trying to create a process ring using named pipes for an assignment, and whenever I call read/write to those files it pauses the execution at that point. I've tried everything I could find for hours now, and have no idea why this is happening.
More context: Process ring with named pipes, passing a token between n processes, from a process i to i+1 in each loop.
Any help would be very much appreciated, and thank you for taking the time!
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <sys/types.h>
#include <fcntl.h>
#include <sys/stat.h>
#include <string.h>
#include <math.h>
#include <errno.h>
#define MAX 50
int main(int argc, char** argv) {
// File descriptors for pipes i and i+1 and token
int fd1, fd2, token = 0;
pid_t pid;
// Pipes path array
char* fifos[2][MAX] = { "pipe1to2" , "pipe2to1" }
...
// Create pipes
for(int i =0 ; i < 2 ; i++){
char* fileToCreate = fifos[i];
if ((mkfifo(fileToCreate,S_IRWXU)) != 0) {
if(errno == 17){ // If a file with the same name exists, this overwrites it
unlink(fileToCreate);
mkfifo(fileToCreate,S_IRWXU);
}else{
printf("Unable to create a fifo; errno=%d\n",errno);
exit(1);
}
}
}
while(true){
char* file = fifos[itr];
fd1 = open(file,O_WRONLY);
if(fd1 == -1){
printf("Open error\n");
return 1;
}
if(write(fd1,token,sizeof(int)) == -1){
printf("Write error");
return 2;
}
close(fd1);
...
}
}

Redirection of stdin and stdout via pipes in C works for external programmes but not for recursive call

I am trying to communicate with forked child processes via pipe redirection of stdin and stdout in C. I already managed to get this to work for shell commands (like ls, for example) executed in child processes. However, I wasn't able to recursively execute the same program and redirect the output (printed by printf(), fprintf() to stdout, ...) via the pipes from the child process to the parent (in this test to stdout of the parent), although this works fine for ls or similar commands.
Here's how I tried to approach this:
I create a pipe, the reading end is for the parent, the child process should write to the writing end.
The Process forks, both processes close the unused end, respectively.
The writing end of the pipe is redirected to STDOUT_FILENO and closed
The child process executes the program recursively (it is called ./to2)
As mentioned, this does work if I execute ls in the child process, but not if I try to call the same program recursively. Here's my test program where I tried to get this to work:
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <sys/socket.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/wait.h>
#include <netdb.h>
#include <errno.h>
#include <time.h>
#include <signal.h>
#include <fcntl.h>
static void usage(void){
fprintf(stderr,"RIP");
exit(EXIT_FAILURE);
}
int main(int argc, char *argv[]){
if(argc > 1){
dprintf(STDOUT_FILENO,"Please work\n");
printf("\n THIS IS A MESSAGE FROM THE CHILD \n");
fputs("Pretty Please!\n",stdout);
fflush(stdout);
exit(EXIT_SUCCESS);
}
int p1[2];
if(-1 == pipe(p1)) {
fprintf(stderr,"pipe\n");
fprintf(stderr,"%s\n",strerror(errno));
usage();
}
int f = fork();
if(f == 0){
close(p1[0]);
if(dup2(p1[1],STDOUT_FILENO) < 0){
fprintf(stderr,"dup2\n");
usage();
}
close(p1[1]);
//I want this to work:
//execlp("./to2", "./to2", "-e");
//This works fine:
execlp("ls", "ls");
exit(EXIT_SUCCESS);
} else if (f == -1) {
usage();
} else {
close(p1[1]);
int w = -1;
if(-1 == wait(&w)) usage();
char b[12];
memset(b,0,12);
read(p1[0],&b,12);
char reading_buf[1];
while(read(p1[0], reading_buf, 1) > 0){
write(1, reading_buf, STDOUT_FILENO);
}
close(p1[0]);
}
}
For testing purposes, the function is called recursively with additional arguments, while the parent program is called without additional arguments (hence the if(argc>1)).
In the final program, endless recursion is being avoided by other means.
Did I understand something wrongly? I am pretty confused by the fact that the only thing that doesn't seem to work is redirecting the output of my own
program...
Thank you very much in advance, any help or ideas are greatly appreciated.
The primary problem is precisely as outlined in the comments — you are not calling execlp() correctly (nor ls in the alternative). You must make the last argument on those function calls into an explicit null pointer, as shown in this code, which is a mostly mildly edited version of what's in the question:
#include <errno.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/wait.h>
#include <unistd.h>
static void usage(void)
{
fprintf(stderr, "RIP\n");
exit(EXIT_FAILURE);
}
int main(int argc, char *argv[])
{
if (argc > 1)
{
dprintf(STDOUT_FILENO, "Please work\n");
printf("THIS IS A MESSAGE FROM THE CHILD\n");
fputs("Pretty Please!\n", stdout);
fflush(stdout);
exit(EXIT_SUCCESS);
}
int p1[2];
if (-1 == pipe(p1))
{
fprintf(stderr, "pipe: %s\n", strerror(errno));
usage();
}
int f = fork();
if (f == 0)
{
close(p1[0]);
if (dup2(p1[1], STDOUT_FILENO) < 0)
{
fprintf(stderr, "dup2: %s\n", strerror(errno));
usage();
}
close(p1[1]);
execlp(argv[0], argv[0], "-e", (char *)0);
fprintf(stderr, "failed to exec %s again\n", argv[0]);
exit(EXIT_FAILURE);
}
else if (f == -1)
{
usage();
}
else
{
close(p1[1]);
char b[13];
memset(b, 0, 13);
if (read(p1[0], &b, 12) < 0)
{
fprintf(stderr, "Failed to read from pipe (%s)\n", strerror(errno));
exit(EXIT_FAILURE);
}
int len = strcspn(b, "\n");
printf("M1 [%.*s]\n", len, b);
char reading_buf[1];
while (read(p1[0], reading_buf, 1) > 0)
{
write(1, reading_buf, STDOUT_FILENO);
}
close(p1[0]);
int w = -1;
if (-1 == wait(&w))
usage();
}
return 0;
}
Two important changes should be highlighted:
This code echoes the first line of data — the one written by dprintf() — whereas the original code just read it and discarded it.
The wait() call is after the input, not before. If the child had more data to write than a set of fixed messages, it could block waiting for the parent to read some of the data, while the parent is blocked waiting for the child to exit. This would be a deadlock.
The usage() function is not appropriately named — it doesn't report how to run the program. I also exit with a failure status, not success, if the child process fails the execlp().
Under peculiar circumstances, the wait() call might report on the exit status from some child other than the one that was forked. It is generally best to use a loop to reap such children. However, the circumstances required are extremely peculiar — the process which launched the parent with an exec*() function must have previously created some children for which it didn't wait, so that they are inherited by the parent process (because the PID doesn't change across an exec*() call).

fprintf returning null after fork() in c

I am trying to open a file with fopen, fork the current process and make the child process write something on the file; when the child process exits, the parents process should read the file's content, but it reads "null", even if the file has been correctly written. No errors are reported.
Here is my code:
#include <stdio.h>
#include <string.h>
#include <errno.h>
#include <sys/types.h>
#include <unistd.h>
#include <stdlib.h>
#include <sys/wait.h>
int main(int argc, char *argv[]){
FILE * sharedFile;
char *fileContent;
if((sharedFile = fopen("testFile.txt","w+")) == NULL){
fprintf(stderr,"Error while opening the file: %s",strerror(errno));
return 0;
}
pid_t pid = fork();
if(pid == 0){
//Child
fprintf(sharedFile,"%s",argv[1]);
exit(0);
}
else{
//Parent
wait(NULL);
if(fscanf(sharedFile,"%s",fileContent) < 0){
fprintf(stderr,"Error while reading file: %s",strerror(errno));
return 0;
}
fprintf(stdout,"File content: %s",fileContent); //Outputs "File content: (null)"
fclose(sharedFile);
}
}
Oddly, if I open again the file in the parent's code after the fork, the output is correct.
What could be the problem?
fileContent has not been allocated any space. Perhaps do this
char fileContent[101];
...
if (fscanf(sharedFile,"%100s",fileContent) != 1) // Prevent buffer overflows. Should return one when successful.

How to launch Preview programmatically with fork and execv?

I'm trying to launch Preview on OSX using fork and execv. When I use fork and execv on Preview the icon pops up in the dock, but nothing is displayed on the screen. The console also displays the two error messages below.
4/20/16 12:18:23.276 PM iconservicesagent[319]: -[ISGenerateImageOp generateImageWithCompletion:] Failed to composit image for descriptor <ISBindingImageDescriptor: 0x7f85aa50b890>.
4/20/16 12:18:23.276 PM quicklookd[1959]: Error returned from iconservicesagent: (null)
Below is some code to reproduce the problem, note you will have to replace
the hardcoded file path in the args array to a valid pdf file path for your system.
#include <stdio.h>
#include <unistd.h>
#include <string.h>
#include <stdlib.h>
#include <errno.h>
#include <stdint.h>
int main(int argc, char *argv[])
{
pid_t pid = 0;
int32_t rtrn = 0;
pid = fork();
if(pid == 0)
{
char * const args[] = {"/users/nah/desktop/file.pdf", NULL};
rtrn = execv("/Applications/Preview.app/Contents/MacOS/Preview", args);
if(rtrn < 0)
{
printf("Can't execute target program: %s\n", strerror(errno));
_exit(-1);
}
_exit(0);
}
else if(pid > 0)
{
int32_t status = 0;
while(waitpid(-1, &status, 0) > 0)
{
}
}
else
{
printf("Can't create child proc: %s\n", strerror(errno));
return (-1);
}
return (0);
}
However If I replace all the fork and execv code and use system(3) like in the example below, Preview opens and displays just fine and there are no error messages in console. So how do I launch Preview using fork and execv instead using system(3) or having to use Objective-C?
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <errno.h>
#include <stdint.h>
int main(int argc, char *argv[])
{
pid_t pid = 0;
int32_t rtrn = 0;
rtrn = system("/Applications/Preview.app/Contents/MacOS/Preview /users/nah/desktop/file.pdf");
if(rtrn < 0)
{
printf("System: %s\n", strerror(errno));
return (-1);
}
return (0);
}
You also need to set the additional arguments that the Mac OS X application system supplies to main(), but you shouldn't be doing any of this:
Preview may or may not be the default PDF viewer for the system it's running on, and if it is not, congratulations, you now have a bewildered and possibly angry user.
If you're dead set on not using Objective-C, what you'll want to do is system("open /path/to/file.pdf");. This will take care of all the tricky business of figuring out what application to use, where it is and how to launch it.

implementing pipeline using fork and pipe

I need to implement nameless pipes using fork for my OS class but I cant get it to work. Its a simple code and have nothing special in it but I just dont get anything. Im trying to run
ls -l | wc -l but I get 0 everytime.
#include <stdio.h>
#include <dirent.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <fcntl.h> // for open flags
#include <time.h> // for time measurement
#include <assert.h>
#include <errno.h>
#include <string.h>
int pid,status;
int pipefd[2];
void my_exec(char* cmd, char** argv)
{
pipe(pipefd); // Fixed
pid = fork();
// pipe(pipefd); // Original
if(pid==0){
close(pipefd[0]);
dup2(pipefd[1],fileno(stdout));
close(pipefd[1]);
execvp(cmd, argv);
}
else {
close(pipefd[1]);
dup2(pipefd[0],fileno(stdin));
while(wait(&status)!=-1);
close(pipefd[0]);
return;
}
}
int main(int argc, char** argv)
{
assert(strcmp(argv[argc-1], "-"));
int i;
for (i = 1; i < argc; ++i) {
if (!strcmp(argv[i], "-")) {
argv[i] = NULL;
my_exec(argv[1], &argv[1]);
argv = &argv[i];
argc -= i;
i = 0;
}
}
char* args[argc];
args[argc-1] = NULL;
for (i = 1; i < argc; ++i) {
args[i-1] = argv[i];
}
if (execvp(args[0], args) == -1)
perror("execvp failed");
return;
}
btw the input for the command Im trying is ls -l - wc -l (instead of | type -)
OK Duck solved it: i should create the pipe before the fork, updated.
Your biggest problem is that you have the fork in front of the pipe. This will effectively have each branch of the fork call pipe() and thus you'll end up with two different pipefd sets, not the same set. Reverse the calling order of the fork() and pipe() and then you're file descriptors in each fork will be the same.
As a side note, you can do a printf() for debugging inside each of the if() statement components to make sure you're never seeing more than two descriptor numbers total.

Resources