I'm trying to recode the UNIX command script
(as it is on OSX). This is part of an exercise for school to help students learn UNIX APIs. We are only allowed to use system calls, more specifically, only those available on MAN(2) pages on Mac OSX (since that's our OS at school).
I have a 'first version' that kind of works. Running a program such as ls
prints the right output to the screen and in an output file.
The problem scenario
I run bash
from within the script
-clone. First issue is I get the following error:
bash: no job control in this shell
I have tried forcing the bash
process into foreground with setpgrp
and setpgid
but that din't change anything so I concluded that was not the problem.
I also tried to understand why the real script
command uses cfmakeraw
(at least on Linux), as seen here, but I don't get it. The MAN page is not very helpful.
The real script
also dup2
s STDIN on the slave
, as seen here, but when I do that, it seems like input isn't read anymore.
However, the bash still runs, and I can execute commands inside of it.
But if I run vim
inside it, and then hit Ctrl-Z to put vim
to the background, the terminal is messed up (which does not happen when I'm in my regular terminal).
So I guess I must have done something wrong. I'd appreciate any advice/help.
Here's the source code: https://github.com/conradkleinespel/unix-command-script/tree/2587b07e7a36dc74bf6dff0e82c9fdd33cb40411
You can compile by doing: make
(it builds on OSX 10.9, hopefully on Linux as well)
And run by doing: ./ft_script
Don't know it it makes more sense to have all the source code in StackOverflow as it would crowd the page with it. If needed, I can replace the Git link with the source.
I don't use OS X, so I can't directly test your code, but I'm currently writing a toy terminal emulator and had similar troubles.
about "bash: no job control in this shell"
In order to perform job control, a shell needs to be a session leader and the controlling process of its terminal. By default, your program inherits the controlling terminal of your own shell which runs your script
program and which is also a session leader. Here is how to make your new slave process a session leader after fork
:
/* we don't need the inherited master fd */
close(master);
/* discard the previous controlling tty */
ioctl(0, TIOCNOTTY, 0);
/* replace existing stdin/out/err with the slave pts */
dup2(slave, 0);
dup2(slave, 1);
dup2(slave, 2);
/* discard the extra file descriptor for the slave pts */
close(slave);
/* make the pts our controlling terminal */
ioctl(0, TIOCSCTTY, 0);
/* make a new session */
setsid()
At this point, the forked process has stdin/out/err bound to the new pts, the pts became its controlling terminal, and the process is a session leader. The job control should now work.
about raw tty
When you run a program inside a normal terminal, it looks like this:
(term emulator, master side) <=> /dev/pts/42 <=> (program, slave side)
If you press ^Z
, the terminal emulator will write the ascii character 0x1A
to the pts. It is a control character, so it won't be sent to the program, but instead the kernel will issue SIGSTP
to the program and suspend it. The process of transforming characters into something else is called "line cooking" and has various settings that can be adjusted for each tty.
Now let's look at the situation with script
:
term emulator <=> /dev/pts/42 <=> script <=> /dev/pts/43 <=> program
With normal line settings, what happens when you press ^Z
? It will be transformed into SIGSTP
by /dev/pts/42
and script
will be suspended. But that's not what we want, instead we'd like the 0x1A
character produced by our ^Z
to go as-is through /dev/pts/42
, then be passed by script
to /dev/pts/43
and only then be transformed into SIGSTP
to suspend the program.
This is the reason why the pts between your terminal and script must be configured as "raw", so that all control characters reach the pts between script
and the program, as if you were directly working with it.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With