For some signals, like SIGINT, I can easily enough set up a trap to handle the signal and continue execution as I see fit. I'd like to add typical behavior for ^q and ^s to a ruby command-line application that I'm fiddling with. Is there a way to do this - particularly, one that is portable so I can use it in Windows, iOS, Linux and Solaris?
EDIT:
It turns out that the signals are never delivered to the process. In fact, running strace on the process and on its parent process, a bash instance, showed that neither the process nor the parent were getting any indication of what was going on. They're simply being suspended.
I may try to have a SIGALARM handler that fires once per second, checks to see if much more than a second has passed since the last alarm, and makes appropriate calls if it concludes that the process has been suspended. There would be false positives on a heavily-loaded system.
In irb enter Signal.list. It will list all the signals you should be able to trap.
Trap a signal in ruby:
Signal.trap("STOP") do
# handle the signal
end
In the terminal enter $ stty -a. It should list signals and their associated key combo (if they have one).
I believe ^s is usually stop and ^q is start.
Although according to this answer, those key combos do not actually send a signal to the running process, but instead to the terminal driver. In that case, kill -STOP <process> can send that signal to your process.
TL;DR No, you can't trap them, because they don't result in signals and the processes under the terminal don't see them and can only detect them heuristically. However, if the point is to be able to use those keybindings in your terminal program, then yes, you can do that by disabling the terminal's special treatment of them.
^q and ^s don't result in signals. It's ^z not ^s that results in the terminal signaling SIGSTOP (EDIT: It's actually SIGTSTP).
What ^s does is tell the terminal to not read the output of the processes that are writing to it. This causes the processes to block on write to the terminal (they can still write to other places and read from stdin, as well as do other things)[1]. ^q tells the terminal to continue reading and displaying the processes output. The processes that have the terminal as standard input don't see these. The terminal sees the keybindings, acts on them, and doesn't pass them on to the processes reading from its terminal device.
You can disable this special behaviour with stty -ixon, and re-enable it with stty ixon. When I disable it, the process that reads while I type says that ^s is byte 0x13, and ^q is byte 0x11.
[1] As an experiment to show this, you can open 2 terminal windows. Execute tty on the second one to find its terminal device. Then, on the first terminal, you can run tee $TTY > $OTHER_TTY with $OTHER_TTY being the terminal device of the second terminal. Once you've done that, you can hit ^s to block writes to the terminal and check this by typing some line. That line will be displayed in the second terminal, but not the first, and thereafter nothing you type will be displayed on either until you hit ^q. What happened here is that after you hit ^s and typed a line, tee could still read it, and output it to its stdout which we redirected to the second terminal. Then, when it tried to write it to the first file passed as argument it blocked because it was the terminal you blocked with ^s. It stayed there waiting for write() to return which it won't until you hit ^q.
Related
I have been reading about ptys from this page's example: http://www.rkoucha.fr/tech_corner/pty_pdip.html. I have two questions:
What is the difference, or the most important difference, between using a pty and using a pipe? From what I have read, both are for inter-process communication, but with a pty the process can "treat it like a normal terminal". What does that mean?
What is a "controlling terminal"? I have read about them but can't understand what they really are. Is the controlling terminal always the pty assigned to the process?
The article you mention is excellent, and hard to improve upon, but it is rather technical. I'll try to give a less technical explanation (bear with me, Unix gurus!)
A pipe is just an unidirectional data channel: it can only be written on one end, and read on the other. For bidirectional inter-process communication you'll always need two pipes. Pipes are excellent to move bits around, but not for much more.
A pty (pseudoterminal) can be read and written on both ends, but it is much more than just a bidirectional data channel. To understand this, it is useful to have a look at a real terminal: On one end there is a process reading keystrokes and sending characters to a teletype or screen. On the other end there is a real human banging away at a keyboard and staring at the above-mentioned screen. Only one end has a file descriptor, the other end is just a connector and a cable.
Historically, terminals have developed many attributes that can be controlled by the programs running on them (like 'echo mode' or 'canonical mode', see termios (3)) Also, a terminal can let the user (by way of the above-mentioned connector and cable) send signals that can be used for 'job control', e.g. by typing CTRL-Z to put a foreground job in the background.
A pty is like a real terminal where both ends are file descriptors:
the slave end behaves exactly like a real terminal : a process that has a descriptor for the slave end ("inferior process") can read from, and write to it, but also set terminal attibutes like echo mode or the interrupt character (e.g. CTRL+C). It will usually not even be aware that is is not connected to a real screen and keyboard.
the master end looks more like a keyboard and teletype for use, not by humans, but by other processes: any process that has opened the the master end can write to it, and will receive echo (but only if the inferior process has set the ECHO attribute on the slave). It can also (on most modern unices) control the session that has the slave as its controlling terminal), e.g. by sending CTRL+Z.
To understand what a controlling terminal is, it is again useful to think about the scenario where a real user is logged in at a real terminal. The user can start a "session", i.e. a collection of processes, some of them in foreground jobs, others in the background.
To prevent chaos, a controlling terminal (i.e. the kernel structure associated with it) keeps track of which processes are in a foreground or background job, and which processes are allowed to read from and write to it. Whenever a process tries something illegal (like a background process reading from the controlling terminal) the operation will fail (with EIO) and the whole job is then stopped by the kernel (using the signal SIGTTIN)
This shows that, just as with a real terminal, only the slave end of a pty can be a controlling terminal, and that the concept only makes sense on a Unix system that supports job control (any Unix system, nowadays)
I have seen tools to daemonize processes.
But I have seen that:
some_command &
Runs process in a daemonized way, is this way bad? how is this way called?
Update
My doubt is that I am calling that command inside an ssh session, will the process last after closing ssh session?
That's not daemonized, that's simply running it as a background process.
A true dameon is a lot more involved; see e.g. http://en.wikipedia.org/wiki/Daemon_(computer_software)#Creation.
The & is an important little character in UNIX; it means "run the command in the background"; i.e., detach it from the window it was started from, so it does not block the command line.
Should the program ever try to read from the terminal window, it will be suspended, until the user "brings it to the foreground"; i.e., brings it to the state it would have had without the & to begin with.
To bring a program to the foreground, use "fg" or "%". If you have more than one background job to choose from ("jobs" will show you), then use for example "%2" to choose the second one.
Important:
If you forget to give the & at the end of line, and the process blocks the command input to the terminal window, you can put the process in the background "after the fact", by using Ctrl-Z. The process is suspended, and you get the command prompt back. The first thing you should do then is probably to give the command "bg", that resumes the process, but now in the background.
http://www.astro.ku.dk/comp-phys/tutorials/background.shtml
Programs like vi, less, screen, when executed, they fill the terminal with their data, and then, if you press c - Z (or terminate the program) the terminal return as it was before the execution of these programs.
How usually a program do that? What is the correct terminology this kind of thing?
PS: The words used in the title may be not correct since I've no even idea about the terminology of this kind of things.
EDIT:
Thank to #Atropo I now know the correct name of these is foreground process,
but, how a program do that? How the program can clear the screen, do its writing and, at the end of the execution, let the shell reappear with all the old writings?
They're called foreground processes.
Usually a foreground processes show the user an interface, through which the user can interact with the program. So the user must wait for one foreground process to complete before running another one.
While you use a foreground process the shell prompt disappears until you close the process or you put it in the background.
By default CTRL-C generates SIGINT signal and CTRL-Z SIGTSTP:
https://en.wikipedia.org/wiki/Unix_signal
To change the behavior you can:
redefine or mask signal handler
disable the key combination for stdin http://linux.die.net/man/3/termios
close stdin descriptor (like daemons do)
What I'm trying to do
My Cocoa app needs to run a bunch of command-line programs. Most of these are non-interactive, so I launch them with some command-line arguments, they do their thing, output something and quit. One of the programs is interactive, so it outputs some text and a prompt to stdout and then expects input on stdin and this keeps going until you send it a quit command.
What works
The non-interactive programs, which just dump a load of data to stdout and then terminate, are comparatively trivial:
Create NSPipes for stdout/stdin/stderr
Launch NSTask with those pipes
Then, either
get the NSFileHandle for the other end of the pipe to read all data until the end of the stream and process it in one go when the task ends
or
Get the -fileDescriptors from the NSFileHandle of the other end of the output pipes.
Set the file descriptor to use non-blocking mode
Create a GCD dispatch source with each of those file descriptors using dispatch_source_create(DISPATCH_SOURCE_TYPE_READ, ...
Resume the dispatch source and handle the data it throws at you using read()
Keep going until the task ends and the pipe file descriptor reports EOF (read() reports 0 bytes read)
What doesn't work
Either approach completely breaks down for interactive tools. Obviously I can't wait until the program exits because it's sitting at a command prompt and never will exit unless I tell it to. On the other hand, NSPipe buffers the data, so you receive it in buffer-sized chunks, unless the CLI program happens to flush the pipe explicitly, which the one in my case does not. The initial command prompt is much smaller than the buffer size, so I don't receive anything, and it just sits there. So NSPipe is also a no-go.
After some research, I determined that I needed to use a pseudo-terminal (pty) in place of the NSPipe. Unfortunately, I've had nothing but trouble getting it working.
What I've tried
Instead of the stdout pipe, I create a pty like so:
struct termios termp;
bzero(&termp, sizeof(termp));
int res = openpty(&masterFD, &slaveFD, NULL, &termp, NULL);
This gives me two file descriptors; I hand the slaveFD over to an NSFileHandle, which gets passed to the NSTask for either just stdout or both stdout and stdin. Then I try to do the usual asynchronous reading from the master side.
If I run the program I'm controlling in a Terminal window, it starts off by outputting 2 lines of text, one 18 bytes long including the newline, one 22 bytes and with no newline for the command prompt. After those 40 bytes it waits for input.
If I just use the pty for stdout, I receive 18 bytes of output (exactly one line, ending in newline) from the controlled program, and no more. Everything just sits there after the initial 18 bytes, no more events - the GCD event source's handler doesn't get called.
If I also use the pty for stdin, I usually receive 19 bytes of output (the aforementioned line plus one character from the next line) and then the controlled program dies immediately. If I wait a little before attempting to read the data (or scheduling noise causes a small pause), I actually get the whole 40 bytes before the program again dies instantly.
An additional dead end
At one point I was wondering if my async reading code was flawed, so I re-did everything using NSFileHandles and its -readInBackgroundAndNotify method. This behaved the same as when using GCD. (I originally picked GCD over the NSFileHandle API as there doesn't appear to be any async writing support in NSFileHandle)
Questions
Having arrived at this point after well over a day of futile attempts, I could do with some kind of help. Is there some fundamental problem with what I'm trying to do? Why does hooking up stdin to the pty terminate the program? I'm not closing the master end of the pty, so it shouldn't be receiving EOF. Leaving aside stdin, why am I only getting one line's worth of output? Is there a problem with the way I'm performing I/O on the pty's file descriptor? Am I using the master and slave ends correctly - master in the controlling process, slave in the NSTask?
What I haven't tried
I so far have only performed non-blocking (asynchronous) I/O on pipes and ptys. The only thing I can think of is that the pty simply doesn't support that. (if so, why does fcntl(fd, F_SETFL, O_NONBLOCK); succeed though?) I can try doing blocking I/O on background threads instead and send messages to the main thread. I was hoping to avoid having to deal with multithreading, but considering how broken all these APIs seem to be, it can't be any more time consuming than trying yet another permutation of async I/O. Still, I'd love to know what exactly I'm doing wrong.
The problem is likely that the stdio library inside is buffering output. The output will only appear in the read pipe when the command-line program flushes it, either because it writes a "\n" via the stdio library, or fflush()s, or the buffer gets full, or exits (which causes the stdio library to automatically flush any output still buffered), or possibly some other conditions. If those printf strings were "\n"-terminated, then you MIGHT the output quicker. That's because there are three output buffering styles -- unbuffered, line-buffered (\n causes a flush), and block buffered (when the output buffer gets full, it's auto-flushed).
Buffering of stdout is line-buffered by default if the output file descriptor is a tty (or pty); otherwise, block buffered. stderr is by default unbuffered. The setvbuf() function is used to change the buffering mode. These are all standard BSD UNIX (and maybe general UNIX) things I've described here.
NSTask does not do any setting up of ttys/ptys for you. It wouldn't help in this case anyway since the printfs aren't printing out \n.
Now, the problem is that the setvbuf() needs to be executed inside the command-line program. Unless (1) you have the source to the command-line program and can modify it and use that modified program, or (2) the command-line program has a feature that allows you to tell it to not buffer its output [ie, call setvbuf() itself], there's no way to change this, that I know of. The parent simply cannot affect the subprocess in this way, either to force flushing at certain points or change the stdio buffering behavior, unless the command-line utility has those features built into it (which would be rare).
Source: Re: NSTask, NSPipe's and interactive UNIX command
Is there a terminal program that shows the difference between input, standard output, error output, the prompt, and user-entered commands? It should also show when standard input is needed vs. running a command.
One way would be to highlight each differently. The cursor could change color depending on if it was waiting for a command, running a command, or waiting for standard input.
Another way would be to have 3 frames -- a large frame on the top for output (including prompt and commands running), a small frame near the bottom for standard input, and an one-line frame at the bottom for command line input. That would possibly even allow running another command to provide input while the previous command is still waiting for standard input.
From http://jamesjava.blogspot.com/2007/09/terminal-window-with-3-frames.html
Hotwire could be a good candidate, but it's not doing that out of the box, AFAIK
For now it appears that there is no such program.
My program gush (Graphical User SHell) does part of this.
It uses different colours for commands and program stdin/stdout/stderr.
Note that the traditional separation of shell and terminal makes this
impossible because the interface between them models an old serial
terminal connection and therefore only has a single input and single
output channel. I get around this problem by combining shell and
terminal into one program.
It would be nice to also indicate when a program is waiting for input,
but I don't think there's any way to detect this, unless you traced the
system calls of the child program to detect when it tries to read stdin.
For interactive programs, you can guess that if the last output did not
end with newline it's probably prompting for input, but this would not
work for non-interactive programs, eg. sed.