====== USB Serial console server ======
If you ever ran a serial console server with a lot of USB dongles you'll find that the numbering of your devices may change due to un-re-plug events or when you reboot the machine where your USB adapters are attached to.
Please see the answers to [[#ref1|my post]] from [[#ref2|Poul-Henning Kamp]] and [[#ref3|Daniel O'Connor]].
Also there is a review open [[#ref4|D21886]] highly related to this.
I have since (in a night hack; forgive the horrible shell) improved the script as I also like to have device names and not just serial numbers.
In addition I have 4-port USB-Serial dongles which means I see the same serial number 4 times.
* /usr/local/etc/devd/usbserial.conf
attach 500 {
#match "system" "USB";
#match "subsystem" "DEVICE";
match "device-name" "(uftdi|umodem|uplcom|uslcom)[0-9]*";
match "vendor" ".+";
match "product" ".+";
match "sernum" ".+";
action "/usr/local/libexec/usbserial ATTACH $sernum $ttyname $device-name";
#action "ln -fs /dev/cua$ttyname /dev/cua_$sernum";
};
notify 500 {
match "system" "USB";
match "subsystem" "DEVICE";
match "type" "DETACH";
match "vendor" ".+";
match "product" ".+";
match "sernum" ".+";
action "/usr/local/libexec/usbserial $type $sernum $ttyname $device-name";
#action "rm -f /dev/cua_$sernum";
};
* /usr/local/libexec/usbserial (remove the first white space and make shell script root executable; hope the wiki doesn't mangle anything else, otherwise check the raw page)
#!/bin/sh
MODE="$1"
SERNUM="$2"
TTYNAME="$3"
DEVNAME="$4"
if test -z "${MODE}" -o -z "${SERNUM}"; then
logger -p daemon.err -t usbserial "$0 mandatory argument empty: '$1' '$2'"
printf "$0 ERROR: mandatory argument empty: '$1' '$2'\n" >&2
exit 1
fi
# Prefixes for tty and cua, for serial and name.
CUA_S_PREFIX="/dev/cua.s."
CUA_N_PREFIX="/dev/cua.n."
TTY_S_PREFIX="/dev/tty.s."
TTY_N_PREFIX="/dev/tty.n."
S="${SERNUM}"
NN="${SERNUM}"
DETACHNODES=""
case "${SERNUM}" in
XXXXXXXX) NN="nanopc-t4.1500000" ;;
FTYYYYY)
FTYYYYY_S_0="${S}.0"
FTYYYYY_S_1="${S}.1"
FTYYYYY_S_2="${S}.2"
FTYYYYY_S_3="${S}.3"
FTYYYYY_N_0="amachine.9600"
FTYYYYY_N_1="bsd42.115200"
FTYYYYY_N_2="ccomp.19200"
FTYYYYY_N_3="dlang.115200"
case "${MODE}" in
ATTACH)
# 4 Ports; needs special treatment; 4x called on attach (assumed in order), 1x on detach
if test -e ${CUA_S_PREFIX}${FTYYYYY_S_3}; then
logger -p daemon.err -t usbserial "$0 4 port serial ${SERNUM} with more device nodes"
printf "$0 ERROR: 4 port serial ${SERNUM} with more device nodes\n" >&2
exit 2
elif test -e ${CUA_S_PREFIX}${FTYYYYY_S_2}; then
S="${FTYYYYY_S_3}"
NN="${FTYYYYY_N_3}"
elif test -e ${CUA_S_PREFIX}${FTYYYYY_S_1}; then
S="${FTYYYYY_S_2}"
NN="${FTYYYYY_N_2}"
elif test -e ${CUA_S_PREFIX}${FTYYYYY_S_0}; then
S="${FTYYYYY_S_1}"
NN="${FTYYYYY_N_1}"
else
S="${FTYYYYY_S_0}"
NN="${FTYYYYY_N_0}"
fi
;;
DETACH)
DETACHNODES="${DETACHNODES} ${FTYYYYY_S_0}:${FTYYYYY_N_0}"
DETACHNODES="${DETACHNODES} ${FTYYYYY_S_1}:${FTYYYYY_N_1}"
DETACHNODES="${DETACHNODES} ${FTYYYYY_S_2}:${FTYYYYY_N_2}"
DETACHNODES="${DETACHNODES} ${FTYYYYY_S_3}:${FTYYYYY_N_3}"
;;
esac
;;
*)
logger -p daemon.info -t usbserial "$0 unknown serial device '${SERNUM}'"
printf "$0 INFO: unknown serial device '${SERNUM}'\n" >&2
;;
esac
case "${MODE}" in
ATTACH)
if test -z "${TTYNAME}"; then
logger -p daemon.err -t usbserial "$0 no ttyname given for '${SERNUM}'"
printf "$0 ERROR: no ttyname given for '${SERNUM}'\n" >&2
exit 1
fi
logger -p daemon.notice -t usbserial "$0 creating symlinks for ${TTYNAME} -> ${S}"
ln -sf cua${TTYNAME} ${CUA_S_PREFIX}${S}
ln -sf tty${TTYNAME} ${TTY_S_PREFIX}${S}
case "${NN}" in
${S}) ;;
*)
logger -p daemon.notice -t usbserial "$0 creating symlinks for ${TTYNAME} -> ${NN}"
ln -sf cua${TTYNAME} ${CUA_N_PREFIX}${NN}
ln -sf tty${TTYNAME} ${TTY_N_PREFIX}${NN}
;;
esac
;;
DETACH)
# Strip any leading space.
DETACHNODES=${DETACHNODES#* }
case "${DETACHNODES}" in
"")
if test ! -L ${CUA_S_PREFIX}${S}; then
logger -p daemon.notice -t usbserial "$0 SKIPPING removing symlinks for ${CUA_S_PREFIX}${S}: `ls -l ${CUA_S_PREFIX}${S}`"
exit 0
fi
logger -p daemon.notice -t usbserial "$0 removing symlinks for ${SERNUM} -> ${S} ${NN}"
rm -f ${CUA_S_PREFIX}${S} ${TTY_S_PREFIX}${S} \
${CUA_N_PREFIX}${NN} ${TTY_N_PREFIX}${NN}
;;
[A-Za-z0-9]*)
for x in ${DETACHNODES}; do
s=${x%%:*}
n=${x##*:}
if test ! -L ${CUA_S_PREFIX}${s}; then
logger -p daemon.notice -t usbserial "$0 SKIPPING removing symlinks for ${CUA_S_PREFIX}${s} / ${n}: `ls -l ${CUA_S_PREFIX}${s} ${CUA_S_PREFIX}${n}`"
continue
fi
logger -p daemon.notice -t usbserial "$0 removing symlinks for ${SERNUM} -> ${s} ${n}"
rm -f ${CUA_S_PREFIX}${s} ${TTY_S_PREFIX}${s} \
${CUA_N_PREFIX}${n} ${TTY_N_PREFIX}${n}
done
;;
*)
logger -p daemon.err -t usbserial "$0 unsupported detach nodes '${DETACHNODES}' for '${SERNUM}'"
printf "$0 ERROR: unsupported number of detach nodes ${DETACHNODES} for '${SERNUM}'\n" >&2
exit 3
;;
esac
;;
*)
logger -p daemon.err -t usbserial "$0 mode '${MODE}' unknown for '${SERNUM}'"
printf "$0 ERROR: mode '${MODE}' unknown for '${SERNUM}'\n" >&2
exit 1
;;
esac
# end
===== References =====
- [[https://lists.freebsd.org/pipermail/freebsd-arch/2021-April/020322.html]]
- [[https://lists.freebsd.org/pipermail/freebsd-arch/2021-April/020324.html]]
- [[https://lists.freebsd.org/pipermail/freebsd-arch/2021-April/020325.html]]
- [[https://reviews.freebsd.org/D21886]]