How can I access a linux character device with D? - linux-device-driver

I would like to turn a led (character device) of an embedded linux board (BeagleBone Black) on and off with a script written in D.
Via the command line a led can be turned on and off (e.g. for led "USER LEDS D2 0") with:
cd /sys/class/leds/beaglebone:green:usr0
echo none > trigger
echo 1 > brightness
echo 0 > brightness
(echo none > trigger disables the default "heartbeat" flashing)
In the D Cookbook on page 93 I found info about how to make linux system calls via the C interface like follows:
void main(){
import core.sys.posix.unistd; // analogous to #include <unistd.h>
string hello = "Hello, world!";
write(1 /*stdout file descriptor*/, hello.ptr, hello.length);
}
Is that a suitable way to access a character device or are there better alternatives?

The unistd calls are indeed the correct way to do it. A character device in Linux is a special kind of file and is accessed the same way: you open it by path, then read or write to it, and close it when finished.
Note that open is actually inside core.sys.posix.fcntl, while read is in core.sys.posix.unistd.
You could also use std.file.write() from the D standard library to be a bit shorter. There's also chdir in there. So your shell example would literally become:
import std.file;
chdir("/sys/class/leds/beaglebone:green:usr0");
std.file.write("trigger", "none"); // write "filename", "data string"
std.file.write("brightness", "1");
std.file.write("brightness", "0");
You don't strictly have to use std.file.write as the full name with the import, I just like to since write is such a common word it clears up which one we mean.
Anyway, this function just wraps up the unistd calls for you: it opens, writes the string, and closes all in one (just like the shell echo!).
One small difference is shell echo sticks a \n at the end of the string. I didn't do that here. If the code doesn't work, try "1\n" and such instead, maybe the device requires that. But I doubt it.
But the std.file.write vs the core.sys.posix.unistd.write aren't that much different. The former is more convenient, the latter gives more precise control over it.

Related

How do I decode xterm responses?

I'm building an application that uses pty.js to open up a pseudo terminal on my computer. I'm getting responses that look like:
]0;ec2-user#ip-172-31-62-237:~[?1034h[ec2-user#ip-172-31-62-237 ~]$ ls
]0;ec2-user#ip-172-31-62-237:~[ec2-user#ip-172-31-62-237 ~]$ pwd
/home/ec2-user
I'm assuming pty.js is sending back a specific encoding, but I'm not sure what the encoding is and how to decode it. Any help would be appreciated, thanks.
Those aren't responses (the terminal would respond), but control sequences sent by an application (not the terminal). I see a few instances (OSC might print as ^[], and CSI as ^[[ if the escape character were shown as ^[):
]0;ec2-user#ip-172-31-62-237:~
looks like the control for setting the window title (from xterm although several programs support it),
OSC Ps ; Pt BEL
OSC Ps ; Pt ST
...
Ps = 0 -> Change Icon Name and Window Title to Pt.
and
[?1034h
looks like another sequence from xterm's repertoire (generally not supported by other programs):
CSI ? Pm h
DEC Private Mode Set (DECSET).
...
Ps = 1 0 3 4 -> Interpret "meta" key, sets eighth bit.
(enables the eightBitInput resource).
For the given example, encoding isn't a factor.
For capturing output from your application, the script program is useful. I use a small utility (unmap) to translate the resulting typescript files into readable form, but cat -v is often adequate for this purpose.
Further reading: XTerm Control Sequences

how to read texts on the terminal inside perl script

Is there any way to capture the texts on termianl screen inside a perl script. I know there are some functions like system,exec,backticks but the problem is that they execute commands FROM the script.For ex:- in terminal i write cd/ (or) ls,and after that i run my perl script which will read what was written on termianl screen(in this case, scipt will capture cd/ (or) ls-whichever was given to termianl). I came with one solution that by passing the commands which you wrote on termianl as a command line arguments to the script,but any other way???
Like this maybe:
history | perl -ne 'print $_'
As I understand it, in a situation where you've typed some stuff into a terminal like this:
[tai#littlerobot ~] echo "Hello"
Hello
[tai#littlerobot ~] perl myscript.pl
You want myscript.pl to be able to access the echo "Hello" part, and possibly also the Hello that was that command's output.
Perl does not provide such a feature. No programming language does or can provide such a feature because the process in which your script/program runs has no intrinsic knowledge about what happened in the same terminal before it was run. The only way it could access this text would be if it could ask the currently running terminal, which will have some record of this information (i.e. the scrollback buffer), even if it cannot distinguish between which characters in the text were typed by you, and which are output. However, I know of no terminal that exposes that information via any kind of public API.
So if you want myscript.pl to be able to access that echo "Hello", you'll need to pass it to your script. Piping history to your script (as shown by Mark Setchell in his answer) is one technique. history is a shell built-in, so it has as much knowledge as your shell has (which is not quite the same knowledge as your terminal has). In particular it can give you a list of what commands have been typed in this shell session. However, it cannot tell you about the output generated by those commands. And it cannot tell you about other shell sessions, so doing this in Perl is fairly useless:
my #history = `tcsh -c history`;
The last thing you could try (though it would be incredibly complicated to do) would be to ask the X server (or Windows if running on that operating system) for a screen shot and then attempt to locate which rectangle the current terminal is running in and perform OCR on it. This would be fraught with problems though, such as dealing with overlapping windows.
So, in summary, you cannot do this. It's nothing to do with Perl. You cannot do this in any programming language.

Real world examples of UNIX named pipes

I usually think of UNIX pipes as a quick and dirty way to interact with the console, doing things such as:
ls | grep '\.pdf$' #list all pdfs
I understand that it's possible to use create named pipes using mkfifo and mknod.
Are named pipes still used significantly today, or are they a relic of the past?
They are still used, although you might not notice. As a first-class file-system object provided by the operating system, a named pipe can be used by any program, regardless of what language it is written in, that can read and write to the file system for interprocess communication.
Specific to bash (and other shells), process substitution can be implemented using named pipes, and on some platforms that may be how it actually is implemented. The following
command < <( some_other_command )
is roughly identical to
mkfifo named_pipe
some_other_command > named_pipe &
command < named_pipe
and so is useful for things like POSIX-compliant shell code, which does not recognize process substitution.
And it works in the other direction: command > >( some_other_command ) is
mkfifo named_pipe
some_other_command < named_pipe &
command > named_pipe
pianobar, the command line Pandora Radio player, uses a named pipe to provide a mechanism for arbitrary control input. If you want to control Pianobar with another app, such as PianoKeys, you set it up to write command strings to the FIFO file, which piano bar watches for incoming commands.
I wrote a MAMP stack app in college that we used to manage users in an LDAP database on a file server. The PHP scripts would write commands to a FIFO that a shell script running in launchd would read from and interact with the LDAP database. I had no idea what I was doing, so I don’t know if there was a better or more correct way to do it, but it worked great at the time.
Named pipes are useful where a program would expect a path to a file as an argument as opposed to being willing to read/write with stdin and stdout, though very modern versions of bash can get around this with < ( foo ) it is still sometimes useful to have a file like object which is usable as a pipe.

TTY in perl, explaination and some examples

So I am trying run a perl debugger inside another perl debugger. I keep readin tty in perl is the solution. Can someone explain to me what tty means ( is it terminal type?) and how is it useful? This is where I read it:
http://search.cpan.org/~rjbs/perl-5.18.0/lib/perl5db.pl#$CreateTTY
The reason I am trying to use tty is because of this question I asked:
Pass argument to perl file in debugger and set breakpoint in file executed by system
Thanks to all the ones who answer, the more you guys tell me what it is, better the idea I get :)
TTY (short for teletype) is basically a special input or output filehandle that connects to the terminal - namely, user input. For nitty gritty details, see:
Unix.SE in-depth answer on TTYs
Text Terminal HOWTO
This is what you need to know for starters (hard to say more since you didn't explain what you need to do with a TTY):
On Unix, it typically maps to /dev/tty device or similar
You can test for it using -t in Perl
As far as debugger, 2 things need to be known at least (if you intend to play with the TTY, the last paragraph is the most important). All data is near-quoted from perldoc perldebug
p expr prints to $DB::OUT filehandle (NOT STDOUT), which in turn is open to /dev/tty.
I think this may be controlled by LineInfo option from PERLDB_OPTS but never played with it so not sure.
Can be affected by the following $ENV{PERLDB_OPTS} options:
TTY - The TTY to use for debugging I/O.
noTTY - If set, the debugger goes into NonStop mode and will not connect to a TTY. If interrupted (or if control goes to the debugger via explicit setting of $DB::signal or $DB::single from the Perl script), it connects to a TTY specified in the TTY option at startup, or to a tty found at runtime using the Term::Rendezvous module of your choice.
This module should implement a method named new that returns an object with two methods: IN and OUT . These should return filehandles to use for debugging input and output correspondingly. The new method should inspect an argument containing the value of $ENV{PERLDB_NOTTY} at startup, or "$ENV{HOME}/.perldbtty$$" otherwise. This file is not inspected for proper ownership, so security hazards are theoretically possible.

How interactive command line utilities actually work?

I grasp the basic concept of stdin, stdout, stderr and how programs work with a command line/terminal.
However, I've always wondered how utilities like less in Linux and git log work because they are interactive.
My current thought is that the program does not quit, writes to stdout, listens to key events and writes more to stdout until the user quits pressing q or sends the close signal.
Is my intuition right or is there more to it? Do they detect the amount of lines and characters per line to determine how much to output? And do they clear the screen always before output?
Very interesting question, even if it's a bit open ended.
As mentioned by #tripleee, ncurses is a foundational library for interactive CLI apps.
A bit of history ...
Terminal == "printer" ...
To understand POSIX "terminals", you have to consider their history ... more specifically, you need to think about what a "terminal" meant in the 70's where you'd have a keyboard+printer attached to a serial cable. As you type, a stream of bytes flows to the mainframe which echos them back to the printer causing the printer to echo the command as you type it. Then, typically after pressing ENTER, the mainframe would go off and do some work and then send output back to be printed. Since it basically a glorified dot-matrix printer, we are talking append-only here. There was no "painting the screen" or anything fancy like that.
Try this:
echo -e "Hi there\rBye"
and you'll see it print "Bye there". "\r" is a carriage return with no line feed. A carriage is that printer part that moves back and forth in an old dot-matrix printer and actually does the printing. So if you return the carriage back to the left side of the page and fail to advance the paper (ie, "line feed"), then you will start printing over the current line of text. "terminal" == "printer".
Monitors and software terminals ... still line-oriented
So flash forward a bit and a revolutionary tech called "monitors" comes about where you have a virtualized terminal display that can be rewritten. So like all good tech, we innovated incrementally by adding more and more special escape codes. For example, check out the ANSI color codes. If you are on a terminal that doesn't recognize those escape codes, you'll see a bunch of gibberish in the output from those uninterpreted codes:
"methodName": ESC[32m"newInstance"ESC[39m,
"fileName": ESC[32m"NativeConstructorAccessorImpl.java"ESC[39m,
"className": ESC[32m"sun.reflect.NativeConstructorAccessorImpl"ESC[39m,
"nativeMethod": ESC[33mfalseESC[39m,
When your terminal sees '\033' (ESC), '[', ..., 'm', it interprets it as a command to change the color. Try this:
echo -e "\033[32mgreen\033[39m"
So anyways, that's the history/legacy of the Unix terminal system which was then inherited by Linux and BSD (eg, macs), and semi-standardized as POSIX. Check out termio.h which defines the kernel interface for interacting with terminals. Almost certainly, Linux/BSD have a bunch of more advanced functions that aren't fully standardized into POSIX. While talking about "standards", there's also a bunch of de-facto terminal device protocol standards like the venerable VT100. Software "terminal emulators" like SSH or PuTTY know how to speak VT100 and usually a bunch of more advanced dialects as well.
Shoe-horning "interactive" onto a "line-oriented" interface ...
So ... interactive ... that doesn't really fit well with a line-printer view of the world. It's layered on top. Input is easy; instead of automatically echoing each keystroke typed and waiting for ENTER (ala "readline"), we have the program consume keystrokes as they come in from the TTY. Output is more complex. Even though the fundamental abstraction is a stream of output, with enough escape codes you can repaint the screen by positioning the "caret" and writing new text on top of old text (just like with my "\r" example). None of this is fun to implement yourself, especially when you want to support multiple environments with different escape codes. .... thus the libraries, of which ncurses is one of the most well known. To get an idea of the funky magic done to efficiently render a dynamic screen into a line-oriented TTY, check out Output and Screen Updating from "A Hacker's Guide to NCURSES".