Find free port to Open Pseudo Terminal Using BSD - c

I want to create a Pseudo Terminal using the BSD API. My understanding is that the Unix 98 API will automatically find a free port with posix_openpt() but with BSD API I need to check/find a free port to connect to. Is this correct?
So I need to do something like this...?
int fd, index = 0;
char serial_port[11]; // = "/dev/ptyp0"
while (true) {
sprintf(serial_port, "/dev/ptyp%d", index);
fd = open(serial_port, O_RDWR | O_NOCTTY | O_NONBLOCK);
if (fd > 0)
break;
index++;
}
Do you know of a Pseudo Terminal tutorial that uses BSD? There are many using Unix 98 API but not many if any BSD API ones.

Using the actual device path is problematic because the pathnames can differ from system to system. Most portable applications which use pseudo terminals long ago were changed to use one of the library functions written to abstract away from the device path.
There is more than one flavor of BSD to consider, e.g., FreeBSD, NetBSD, OpenBSD (and others of course, including OSX). xterm's configure script identifies features from each. All have openpty in the "util" library, providing its prototype in util.h
POSIX provides posix_openpt which combines the functionality of openpty with others to provide a simpler interface. However (though a documented interface), it is known to not work properly with OSX (see for example OSX 10.7.5 UTF-8 encoding over ssh as well as xterm's changelog).
Here are manpage links:
FreeBSD
NetBSD
OpenBSD
OSX

Related

How does the libc function isatty() work?

I searched the linux repo and couldn't find a definition for it, so I guess it's something that comes with C or something like that? I'm trying to understand how isatty is able to tell whether a file descriptor is a terminal or not, and what it even means to "be a terminal," in technical language.
I'm not really sure where to find its implementation, and if it's in assembly I won't really be able to follow along with it very easily.
The general strategy for implementing isatty is to attempt a tty-specific ioctl operation on the file descriptor, and check for ENOTTY error result. Traditionally, TCGETS, which is the backend for the tcgetattr function, is used, but this is slightly dangerous since the ioctl number for it on Linux clashes with legacy OSS sound devices, and if the file descriptor actually refers to a certain type of MIDI device, it will make changes to the device. In musl libc, we use TIOCGWINSZ, the "get window size" operation, whose number was not inadvertently reused for any other types of devices and which reliably fails with ENOTTY for non-tty devices.
In theory, you could do it with fstat and check the st_rdev field for the device major number, but this would require a hard-coded list of all device majors which are ttys, and would have broken when new types were added (e.g. USB-serial/ACM devices, uartlite devices, etc.).
isatty(3) is a library function (you won't find anything about in the linux kernel), and is usually implemented by calling tcgetattr(3) and checking its return value.
For example, in the GNU C library (glibc):
/* Return 1 if FD is a terminal, 0 if not. */
int
__isatty (int fd)
{
struct termios term;
return __tcgetattr (fd, &term) == 0;
}
tcgetattr(3) itself will resolve to some ioctl like TCGETA or TCGETS.
Notice that isatty(3) will also return true for a master side of a pseudo-tty, which isn't really a tty -- most tty related ops performed on it will actually apply to its slave side.
On linux, isatty(3) will also return true for /dev/console, which again, isn't a real tty (it cannot be made the controlling tty of a process).
On linux, you can obtain a list of all the tty drivers on your system with their major and minor numbers via cat /proc/tty/drivers. Of course, that only reflects the modules which have been loaded.

who call tty_open() in linux kernel?

For mouse, keyboard and joystick drivers, it may X call the 'open' then using these drivers.
( when I check CentOS 7 (text mode only) in VirtualBox, I didn't see X after executed lsof /dev/input/event2 ( keyboard ), but my keyboard still working )
How about tty_open() ?
According to a call trace, we can roughly know the sequence:
( at least, we know someone called 'sys_open' )
https://bugzilla.redhat.com/show_bug.cgi?id=630464
However, I still don't know who calls the 'open'?
When I check CentOS 7, text mode only, in VirtualBox, I didn't see X after executed lsof /dev/input/event2 (keyboard), but my keyboard still works
That is because you use the virtual console then, one of the /dev/ttyN devices. These are directly wired to the Linux input event subsystem inside the kernel itself (by the vt module); essentially all keyboard-like devices act as inputs to the currently active virtual terminal.
X itself uses a virtual console, just so that the kernel can switch between it and any text-based virtual consoles.
How about tty_open()?
If you run sudo lsof /dev/tty[0-9], you can see which processes are accessing a virtual console.
The processes with getty in their name are the ones that provide login terminals. (The ones that are used with serial terminals are very similar; in fact, many getty programs can handle both virtual consoles and serial terminals just fine.)
When you log in, that getty launches login (program!), which in turn starts the default shell defined for that user (see getent passwd username; it is the last field, and it must be one that is listed in /etc/shells to be allowed).
The kernel itself supports switching to a different virtual console via Ctrl+Alt+Fn (F1 for tty1, F2 for tty2, and so on). If you use suitable graphics drivers, you can even switch between Xorg and virtual consoles. (Usually, Xorg is run on tty6 or tty7, but that varies from distribution to distribution.) The Ctrl+Alt+← and Ctrl+Alt+→ can also usually be used to switch to the previous or next virtual console.
Thanks for Nominal Animal for the information.
I am tracing linux 2.0 ( https://mirrors.edge.kernel.org/pub/linux/kernel/v2.0/ ), thing maybe a little different.
Sorry, I can't find an online Linux 2.0 source to link reference.
For keyboard, in text mode, I think no one calling 'open' in kernel,
In 'int tty_init(void)' ( tty_io.c ), it will call 'kbd_init();'
then we can see:
request_irq(KEYBOARD_IRQ, keyboard_interrupt, 0, "keyboard", NULL);
therefore, keyboard HW can work with this IRQ & callback ('keyboard_interrupt').
For tty_open(), I finally see it in main.c
open("/dev/tty1",O_RDWR,0);
For the newer version of kernel, I think this part migrated to getty application, that's why I can't find it in kernel source.
tty_* routines are UNIX hardware independent code to implement the terminal interface in the kernel. They are responsible of the tty disciplines, the job control stuff and the linemode processing of characters (including the generation of signals on Ctrl-C for example) They also implement the interface to tty/pty pairs and the like.
This is common code to include all the common functionality of the terminal drivers into any kind of hardware you can have attached for (console keyboard/display is just one example, but you have, at least, uart RS-232C interfaces, usb serial dongles, PCI serial line multiplexors, etc)
Terminal functionality dates from the ancient v7 unix, and has many improvements coming from BSD unix (like job control)
By the way, linux implementation of serial interface is not very good, you should look at the BSD implementation for a good one.

How to call Linux kernel driver functions from a userspace program?

How can I write a C program (in userspace) to call functions that are part of a kernel driver? If it's not possible to do directly, how else do I do it?
CONTEXT: I am trying to use the PWM pins of my single-board computer (Intel NUC DE3815TYBE) so that I can control fans. A linux driver called pwm_lpss allows control of these pins (driver developed by Intel, source code here). I have verified that this driver is installed by using the lsmod command. Here is the driver information after typing modinfo pwm_lpss:
filename: /lib/modules/3.19.0-25-generic/kernel/drivers/pwm/pwm-lpss.ko
license: GPL v2
author: Mika Westerberg <mika.westerberg#linux.intel.com>
description: PWM driver for Intel LPSS
srcversion: 44AA14AF3E2F96C813770A8
depends:
intree: Y
vermagic: 3.19.0-25-generic SMP mod_unload modversions
signer: Magrathea: Glacier signing key
sig_key: 6A:AA:11:D1:8C:2D:3A:40:B1:B4:DB:E5:BF:8A:D6:56:DD:F5:18:38
sig_hashalgo: sha512
So I know where the driver module is (the pwm-lpss.ko file) and I have the source code which I know has a function in it called pwm_lpss_config() that I'd like to use. How do I call the function from my userspace C program? How would I go about #including it? Or is this not possible to do from userspace?
Unfortunately Intel has provided zero documentation for how to use this driver. I thought drivers normally map their functionality to some user-accessible file. I was able to find some PWM-related files after some digging, but I haven't been able to find a file that looks like it can set PWM duty cycle/frequency.
It's a standard Linux PWM driver, so no special documentation is necessary.
Check the /sys/class/pwm/ directory. (/sys is the interface the kernel provides for access to its data structures. It just looks and acts like a filesystem.) You should have something like /sys/class/pwm/pwmchip0/. Each such directory corresponds to a PWM chip.
The directory will have the following entries. You may need superuser privileges to access these (as you wouldn't want everybody to mess with them):
npwm: Read this to find out how many PWM channels this chip has.
export: Write a channel number (0 to whatever-the-number-in-npwm-1) to make that channel available via this sysfs interface
unexport: Write a channel number to remove the channel from sysfs interface control
Each PWM channel exported to be used via the sysfs interface will show up as a subdirectory named pwmN, where N is the channel number. Here, you can read and write to entries
period: Total period (off + on) in nanoseconds.
duty_cycle: On time in nanoseconds. Must be less than period.
polarity: If the chip supports reversing the signal polarity, you can write inversed here to invert the polarity; normal is the default/normal polarity.
enable: 1 if enabled, 0 if disabled.
When reading or writing to these entries, no special locking is necessary. The kernel will receive all data in one write(), and return all data in one read() operation. When a write() succeeds, the kernel has applied the setting.
some ioctl ? The ioctl() function manipulates the underlying device parameters of special files.
Along the lines
fd = open("/dev/pwm0", O_RDONLY); // put whatever device you've got
if (ioctl(fd, STATUSGET, &status) == -1) // magic constant should be set
....
} else {
....
}

Cross-platform sockets

I know, Windows doesn't use UNIX sockets while Mac OS does. Until this point my software was cross-platform without any code changes. But now I want it to do some network communication. I know about POSIX sockets, but I know nothing about Windows' ones. The goal is to implement a simple cross-platform socket server.
Could you please explain to me the differences between POSIX and Winsock sockets and how I may go about writing cross platform networking code?
WinSock versus POSIX Sockets
WinSock and POSIX sockets work in a similar manner - mainly because Windows sockets were originally based on code from BSD:
Although these proprietary BSD derivatives were largely superseded by the UNIX System V Release 4 and OSF/1 systems in the 1990s (both of which incorporated BSD code and are the basis of other modern Unix systems), later BSD releases provided a basis for several open source development projects, e.g. FreeBSD, OpenBSD, NetBSD, Darwin or PC-BSD, that are ongoing. These, in turn, have been incorporated in whole or in part in modern proprietary operating systems, e.g. the TCP/IP (IPv4 only) networking code in Microsoft Windows and most of the foundation of Apple's OS X and iOS.
However, there are a few things you'll need to handle differently if you want to write "socket-library-agnostic" code.
Note: The following examples have been tested using Code::Blocks and GCC on Windows XP (x86) and Debian Testing (AMD64).
The header and lib files are different
You'll need to include different header files depending on whether you're using Windows or not:
#ifdef _WIN32
/* See http://stackoverflow.com/questions/12765743/getaddrinfo-on-win32 */
#ifndef _WIN32_WINNT
#define _WIN32_WINNT 0x0501 /* Windows XP. */
#endif
#include <winsock2.h>
#include <Ws2tcpip.h>
#else
/* Assume that any non-Windows platform uses POSIX-style sockets instead. */
#include <sys/socket.h>
#include <arpa/inet.h>
#include <netdb.h> /* Needed for getaddrinfo() and freeaddrinfo() */
#include <unistd.h> /* Needed for close() */
#endif
You'll also need to link with Ws2_32 lib file on Windows.
WinSock requires initialisation and cleanup.
The functions below illustrate how you can initialise WinSock v1.1 and clean up afterwards:
int sockInit(void)
{
#ifdef _WIN32
WSADATA wsa_data;
return WSAStartup(MAKEWORD(1,1), &wsa_data);
#else
return 0;
#endif
}
int sockQuit(void)
{
#ifdef _WIN32
return WSACleanup();
#else
return 0;
#endif
}
Socket handles are UNSIGNED on Winsock
For POSIX-style sockets, you can simply use int to store a socket handle. Invalid sockets are indicated by a negative value.
However, WinSock sockets are UNSIGNED integers, with a special constant (INVALID_SOCKET) used instead of negative numbers.
You can abstract the differences by typedefing SOCKET as int on POSIX and hiding the "valid socket" check behind a macro or function.
Sockets are closed differently
The function below illustrates the differences:
/* Note: For POSIX, typedef SOCKET as an int. */
int sockClose(SOCKET sock)
{
int status = 0;
#ifdef _WIN32
status = shutdown(sock, SD_BOTH);
if (status == 0) { status = closesocket(sock); }
#else
status = shutdown(sock, SHUT_RDWR);
if (status == 0) { status = close(sock); }
#endif
return status;
}
In general though, they're pretty similar.
If you stick to "common" functions (such as send() or recv()) and avoid platform-specific stuff (such as WSAWaitForMultipleEvents()) then you should be fine.
I can also suggest the plibsys library: works on both Windows and UNIX systems (see the full list on the project page) with various compilers. Supports IPv4 and IPv6. It has the tests where you can see the usage examples. The library itself is lightweight and portable.
There are many libraries and toolkits that support cross platform sockets, depending on what you are doing, you can use (to name a few):
openssl
apache portable runtime
libtcl
If you don't want to have a dependency on an external library, all of the above packages have fairly permissive licenses, so you can use their code as a reference.
The regular sockets (those in AF_INET address family) which you need to build a socket server are equally supported on all platforms.
Do not confuse them with Unix sockets (those in AF_UNIX address family) - such sockets are highly specific for a Unix world, and are used for a highly specific goals. You wouldn't ever need them for a simple socket server application.

How stable are major and minor mode of a chardev?

I'm working on a serial port library, and I am thinking on using the major/minor mode
of the character device to check whether the given file is a platform serial port, a
pty or a usb serial port, in complement of using other frameworks that exist under
Linux or OSX.
Actually, for finding out whether a file is an USB serial port, or a platform serial
port, there are ways using the available frameworks, like libudev on linux or IOKit
on OSX. But I think that for checking a PTY file, the only way is using good old
stat():
#if defined(OS_LINUX)
#define PTY_MAJOR_NODE 136
#elif defined(OS_MAC)
#define PTY_MAJOR_NODE 16
#elif defined(OS_SOLARIS)
#define PTY_MAJOR_NODE 24
#endif
bool is_pty(const char* file) {
struct stat filestat;
if (0 == stat(file, &filestat)
&& S_ISCHR(filestat.st_mode)
&& major(filestat.st_rdev) == PTY_MAJOR_NODE) {
return true;
}
return false;
}
So far I found out on my debian linux that the PTS chardev all have a major mode of
136, and on my OSX, all PTS have a mode of 16. Crawling on ddg, I found out
Solaris may use a major mode of 24.
I could find many resources online talking about what are PTY/PTS and their history.
The manpage of openpty, pty or pts - though that one give major and
minor of /dev/ptmx - do not talk about major/minor mode of PTS devices. And no
resource listing the Major modes accross unices.
So here are my questions:
are the major mode of PTS (and by extension other serial chardev) stable for a given Unix flavor? (I'm looking for something stable at ±2 years)
where are those defined? I guess it's a kernel driver that handles that, isn't it?
is it a good idea to rely on major mode of the chardev to detect what kind of device this is?
N.B.: I have hesitated to post on unix.SE, but as I'm in the context of using that
in code, I considered this is more a question to ask here, on SO.
Edit: I posted a related question on unix.SE asking for help finding other major modes and look how stable they are accross systems. My guess is that if nobody has an answer, at least we can query the systems and look at the sources.
Major and minor device numbers are defined at compile or link/load time depending on the hardware involved. Adding an additional SBUS card to a Solaris machine might (must?) have an arbitrary major device number. I know mine did.
In short, I don't think major/minor device numbers are going to do what you want.
Consider Debian Linux Ports https://www.debian.org/ports
I can't imagine that the SPARC, s390, MIPS, PowerPC, and ARM architectures all use the same major/minor numbers; the bus architectures are too different.

Resources