Managing stdout/stdin when writing a Linux shell - c

I am working on a school project, and though it's not required, I want to implement this functionality. With that said, I can't share code, but I think it's irrelevant in this case.
When using fork(), my understanding is that the child process created inherits stdin and stdout, as the child inherits all the file streams from the parent.
My shell requires background capability, and while it technically already has that, if the "background" program runs, it still receives all the data from stdin and continues output to the screen which is just a jumbled mess. For the record, my instructor's compiled sample shell does the same thing, but I don't want that to happen!
I'm pretty certain I should be using a combination of pipe(), fork(), and dup2(), but I can't put it all together. I understand fork, but I don't understand how pipe or dup2 works and how I should implement it in the shell. I'm thinking something along these lines:
thePipe[2] = pipe();
pid = fork();
close stdin/out on child somehow if backgrounded
But I don't understand the functionality of pipe() or dup2() so I'm stuck.
Thanks!

You don't want pipes here. Processes run in an interactive shell should share their standard file descriptors with the shell — doing otherwise would break a lot more things (including the child processes' ability to determine they're running interactively, and to interact with the tty to handle things like window size changes). It'd also seriously complicate pipelines. Don't do it.
The missing piece here is process groups, which are described in the "General Terminal Interface" section of the Open Group UNIX specs. In brief, the kernel can be made to explicitly recognize a "foreground process group" for the terminal. If a process that isn't in this group tries to read from or write to the terminal, it is automatically stopped.
A brief walkthrough of what is necessary to make a properly functioning shell is available as part of the GNU libc manual, under "Implementing a Job Control Shell". Try following their instructions and see how that goes.

Related

Know if process has been called by exec()

Is there any way to know if a process has started to run from a call of exec() or has started from the terminal by the user?
Helpful to you: child and parent process id;
getppid() returns the process ID of the parent of the calling
process. This will be either the ID of the process that created this
process using fork(), or, (!!!CARE!!!) if that process has already terminated, the
ID of the process to which this process has been reparented;
I would also consider adding additional program arg.
All programs are started by a call to exec family of functions.
When you type a command in the terminal, for example, it searches for the binary executable, forks and calls exec in the child process. This will substitute the binary image of the calling process (the terminal) for the binary image of the new program. The program will execute and the terminal process will wait.
There is this absolutely awesome answer by paxdiablo on the question Please explain exec() function and its family that will surely help you understand how exec works.
In Unix, all processes are created by using the fork system call, optionally followed by the exec system call, even those started by a user (they are fork/exec'd by the user's shell).
Depending on what you really want to do, the library function isatty() will tell you if stdin, stdout or stderr are file descriptors of a tty device. i.e. input comes from a terminal, output goes to a terminal or errors go to a terminal. However, a command like
myprog < somefile 1>someotherfile 2>errorfile
will fool code using isatty. But maybe that is what you want. If you want to take different actions based on whether there is a user typing input from a keyboard or input is coming from a file, isatty is what you need.

Running multiple forked processes and constantly reading their standard out, while printing to their standard in

I'm looking to run X amount of processes that I'm able to iterate through in order to run programs where there's a master and 'slaves' that take the masters orders and return a string.
I'm writing in C. I'm wondering how I'd be able to set up pipes and forking between there processes to read from standard in and out. I'm currently able to have them work one at a time until the are killed, but I would like to simply read one line then move to the next process. Any help?
Generally, the common strategy for this sort of programming is to set up an event loop.
You would set up pipes and connect them to stdin and stdout of your program.
You don't specify what language you're using.
In C, you would create two pipes, one for reading, and one for writing.
Then you would fork. After the fork, in the child, you close stdin and stdout, and you use the dup2 system call to copy one end of the pipe filedescriptors to the child.
In the parent, you connect each process to an event loop, which lets you know when one of your FDs is ready for reading or writing.
Take a look at these class notes for discussion of using pipes and dup2.
Here's an introduction to libevent, one of the common event loops for C.
For other languages you'll do something similar. For example for Python, take a look at the asyncio support for subprocesses.

How to continuously monitor process creation in Linux?

My process launches a process - let it be a shell in this example, but it's applicable to any process really. I need to get notified when the shell creates new processes and to obtain their PIDs.
I can take a snapshot of the whole process tree at any given time (well, pstree can), but how do I monitor creation of new processes by a process with a given PID?
So far I've found several ways to do so at How to monitor an external process for events by its PID in C? none of which really solve my problem:
Monitoring NetLink proc interfaces. Problem: requires root permissions which I do not have.
Custom library overriding the syscalls loaded into the shell process by LD_PRELOAD. Problem: it will be inherited by the children of the shell as well, and I do not want that - I only want to monitor the shell.
ptrace()ing the shell. Problem: flags that notify the parent (i.e. my process) about creating new processes, i.e. PTRACE_O_TRACEFORK, PTRACE_O_TRACEVFORK and PTRACE_O_TRACECLONE propagate ptrace()ing to child processes, and I only want to monitor the shell.
Making the shell cooperate. Problem: In BASH command callbacks (as used in undistract-me) are very hacky. I'd also prefer to avoid shell-specific code.
I feel like I'm missing something simple here. I feel like I could make one of the above solutions work with more hacks, but... surely I don't have to resort to the big guns like LD_PRELOAD and ptrace() for such a simple task, do I?
JFYI I'm coding this in Vala, but C snippets are welcome too.
No generic solution has been found so far so I had to resort to making the shell cooperate:
ZSH has pre-exec hook documented in
http://zsh.sourceforge.net/Doc/Release/Functions.html
KSH has a
debug hook documented in http://www.manpagez.com/man/1/ksh/
a hack that adds pre-exec to BASH can be found in
https://github.com/jml/undistract-me
I simply write callback commands into the relevant environment variables depending on the shell.

C - execvp() interprocess communication

Hi all I am new to C so sorry if I am very lost. I am having trouble with this multi-threaded web server I am trying to create. I am attempting to...
have a thread create a new thread
have that new thread execute execvp() to call a different C program on my machine
have that new thread return streams of data from the execvp()
I was thinking about using pthreads to spawn a new process to run execvp() and have it return the data through a pipe. But is that even necessary? Don't pthreads share memory?
Also, I was maybe thinking about using fork() instead of a pthread and have the child send data back to the parent through a pipe.
Can you please help guide me in the correct direction.
What you're looking for is a combination of fork(), one of the exec functions, and pipe() (or maybe socketpair() or something, but pipes work too).
Threads share memory, but execvp() would create a completely new process replacing the caller process -- and even if this process shared memory with its parent (which I'm not sure it does!), the newly run program wouldn't know how to use that memory.
The proper way is to open a pipe when you still have one process, fork() into two processes (parent and child), and have the child call execvp(). The child can now write into its end of the pipe, and the parent can read from the other end.
Remember to wait() for the child to end.
Have you written your non-blocking, single-threaded web-server yet? How would you expect to measure the benefits of multithreading if you don't have something to compare it against? It's far easier to determine where the best performance gains are if you expose a single-threaded project to concurrency, than it is to guess and suffer with a poor framework for the rest of the project's life.
Creating threads is easy, but you really need to read the pthread_create manual first. How else can you trust that your project is handling errors correctly? I also suggest reading about the other pthread functionality. I'm happy to help you resolve issues if you show me that you're trying to resolve them yourself, by the way. I won't bother spoonfeeding you.
As mentioned by aaaaaa123456789, you wouldn't want to spawn using pthread_create/execvp as this would replace your entire program environment (including all of your threads) with the new process.

fork to new cygwin terminal

I have this program that forks and I was wondering how to get it to fork to a separate terminal so the parent and child would have their own windows and stop fighting each other. I am trying to accomplish this with cygwin, any ideas?
The general answer is that it's not possible. However, it can be hacked around by using two different programs, one that does the fork, and then the child executes a new shell which might open a new window, and let that shell run the second program.
Or you can use something like ncurses to split the terminal window into two separate regions and use one region per process.

Resources