Ad-hoc Serial Port Console

Hello,

I would like to be able to add the ability to log into my routers by plugging in a USB serial adapter cable to an available USB port and accessing a console from there.

To this end, I have installed the kmod-usb-serial-ftdi and kmod-usb-serial-pl2303 modules and the agetty program.
I have also placed the following in the file /etc/hotplug.d/tty/00-agetty:-

#!/bin/sh

if [ "$ACTION" = add ]; then
    if case $DEVNAME in ttyUSB*) ;; *) false;; esac; then
        logger -t yaaaay "Spawning agetty for $DEVNAME"
        /usr/sbin/agetty -L 38400 $DEVNAME vt100
    fi
fi

This appears to launch agetty as expected whenever I connect the cable, but it also blocks "hotplug-call" until agetty terminates.

Squillions of references on the Internet tell me to instead execute "systemctl enable serial-getty@ttyUSB0.service", but that's for systemd-based systems. :roll_eyes:

I think that I need a procd service for agetty, which should start an instance whenever one of these hotplug events is received (and presumably, to kill the instance when a "remove" event occurs).

Given that more than one serial cable might be possibly connected, I would need to manage one instance of agetty per port.

Can anyone give me some advice on how to write this service, or if this is the wrong approach? :face_with_spiral_eyes:

I've never seen this done... it may be possible if you're looking for a functional equivalanet of an 'ssh' session once the system is fully booted, but you almost certainly will not be able to get this to work for anything prior to the (near) completion of the boot cycle (so reading boot logs won't work).

That said, why not use the actual serial console on your device? Many devices have a set of pin-headers of pads to which you can connect the adapter and then connect the USB to your host computer.

Something is indeed very off with your story…

These ftdi/ pl2303/ cp2102/ ch340 USB2serial adapters are one-way only, they allow you to access a (typically 3.3V) serial console on another device, which -in case of OpenWrt- would give you access to a running root shell without a need for authentication (running getty is possible, but a bit more advanced). Plugging the USB side into the router itself (which would imply installing the referenced kmods) doesn't make any sense, as you can only use it once you have logged into the router via ssh - but at that point, you already have a running root shell, rendering the whole point of this exercise obsolete. And as you do depend on a running ssh session, this wouldn't give you any debugging abilities either - as it only works as long as the router is booted and fully working. Of course using this to debug another device might be useful.

There is no way to go the other route, of using these adapters to debug the system you've plugged them in from the USB side.

1 Like

Actually this could work. Use two adapters wired TX to RX (null modem) and plug one into the router and one into the PC.

When an adapter is plugged into the router, it needs to launch a login process such as the one that starts at boot on the built-in serial port. The one plugged into the PC would be used as normal with terminal software.

1 Like

I've done something similar, but it was over Bluetooth, and didn't require any login, but it worked just fine...

You're correct, I want a "late" console, created and destroyed based upon the presence of a USB adapter.
It would be an option in case I foul up the network config, still require a username/password to access, etc.
Given that I would like to use this for all of my OpenWrt routers, I would prefer a solution that's hardware mod-free. :innocent:

For testing, I am using a FTDI cable which has a serial adapter built into the USB connector either side of the cable. So both the router and client PC have a serial interface.
I also have single adapter PL2303 cables left over from a previous project, which can be paired with a special "gender changer" using the null modem pinout.

I'm not entirely certain how to do this, but you'll certainly need to roll your own images.

I'd start by just getting the general serial port working -- test it with the actual UART from another system... this maintains the typical use-case of those devices. Once you've proven that the adapter works as expected, you'll hopefully be able to figure out a way to open that serial port and use it as a console. Final step will be linking that with hotplug (I think).

1 Like

Definitely don't need to roll your own images. Richard, this is a pretty cool idea, spinning up agetty when a new serial port is hotplugged.

Did you try the obvious thing of putting agetty in the background, storing its PID in a file, and killing that PID when $ACTION = remove ?

I'm trying to do the same thing except that I'm not concerned about multiple USB serial ports. The idea is that if I somehow screw up my network, I can still get into the device to effect repairs. I have the following in /etc/hotplug.d/tty/00-agetty:

if [ "$ACTION" = add ]; then
    if [ "$DEVNAME" = "ttyUSB0" ]; then
        logger "Spawning agetty for $DEVNAME"
        /usr/sbin/agetty 115200 $DEVNAME vt100
    fi
elif [ "$ACTION" = remove ]; then
    if [ "$DEVNAME" = "ttyUSB0" ]; then
        logger "Killing agetty for $DEVNAME"
        killall agetty
    fi
fi

It seems to work, in that the scripts run and agetty gets started and stopped. However, I et a bunch of errors in my logs that I don't know how to handle:

user.notice root: Spawning agetty for ttyUSB0
authpriv.warn agetty[23513]: /dev/ttyUSB0: cannot get controlling tty: Operation not permitted
authpriv.warn agetty[23513]: /dev/ttyUSB0: cannot get controlling tty: Operation not permitted
authpriv.warn agetty[23513]: /dev/ttyUSB0: cannot set process group: Not a tty
authpriv.warn agetty[23513]: failed to create reload file: /run/agetty.reload: No such file or directory

Any suggestions on how to address or suppress these errors?

This StackExchange answer suggests you can fix the errors by using exec /usr/sbin/agetty instead of running it as a subprocess.

Seems plausible to me.

Huh, DDG doesn't return that result. Guess I should have tried Google too.

But no, exec /usr/sbin/agetty ... didn't help. Creating /run got rid of the "failed to create reload file" message but I still get the tty errors. Oh well, it works; I can live with a few extraneous error messages in my logs. It's not like I intend to use this thing very often (hopefully never, in fact).

Current version of /etc/hotplug.d/tty/00-agetty:

if [ "$ACTION" = add ]; then
    if [ "$DEVNAME" = "ttyUSB0" ]; then
        logger "Spawning agetty for $DEVNAME"
        start-stop-daemon -S -x /usr/sbin/agetty -b -m -p /run/agetty.pid -- 115200 $DEVNAME vt100
    fi
elif [ "$ACTION" = remove ]; then
    if [ "$DEVNAME" = "ttyUSB0" ]; then
        logger "Killing agetty for $DEVNAME"
        start-stop-daemon -K -x /usr/sbin/agetty -p /run/agetty.pid 
        rm /run/agetty.pid
    fi
fi

What you really need, in order to nix those messages, is to make agetty a session leader. Exec only does that if the calling process is a session leader and when I think about it's no surprise that the hotplug script is not run by a session leader.

So probably you want to run setsid here, which is in the utils-linux package.

This forum post describes someone with the same situation you have.