I am implementing a simple shell written in C on with proper job control and I have some confusion as to how can a builtin command get to run in background meaning as a part of a background job?
My machine: x86_64, linux 6.1.38-1
For now the way I handle executing builtin commands is avoiding to fork the shell process and just normally execute the builtin_function()
corresponding to that builtin command.
Other non-builtin commands are handled by fork()
ing the process and running exec()
.
For each non-builtin command there is a (my custom) process_t
struct which holds pid_t
of that fork and some other stuff, this gets then inserted into the (my custom) job_t
struct that holds all of the process_t
structs for that job/pipeline and most importantly the pid_t
of that process group.
Using this approach I can correctly print to the terminal all the processes certain background job holds and I can internally manage the status of a job/process very easily.
Now the big question mark for me is how can I achieve this for a builtin command, I can't create a process_t
for it because the command doesn't require fork()
ing so the pid_t
is exactly same. Lets say I create struct process_t
for the builtin command and give it the same pid_t
as the current process; what happens if user wants that pipeline/job to run in background but the builtin command in that job/pipeline is actually all the time running in the foreground potentially blocking the terminal input.
What comes to mind is doing a separate function that also fork()
s the main process and checks if the command is builtin and executes it and quits that process with some status
(-1
status if command is not builtin).
Then if command was not builtin fork()
again and run it with exec()
.
This would actually allow it to be run in the background but I don't know if it is an optimal way of doing things.
Or the other way around would be to actually pack executable binary files that correspond to each "builtin" command and then I can truly fork and exec them...please help.
The idea in your last paragraph is too complicated. All you need is: Fork, then either call a routine to execute a built-in command (and exit afterward) or call exec
to execute a non-built-in command.