Skip to content

Instantly share code, notes, and snippets.

@afresh1
Last active Jan 11, 2021
Embed
What would you like to do?
Helper to generate an /etc/remote file from a template by looking up a serial port from its serial number. If you don't know which `dv=` device to use, specify an `iSerial=$serial` instead.
#!/usr/bin/perl
use v5.30;
use warnings;
%ENV = ();
use OpenBSD::Pledge;
use OpenBSD::Unveil;
# Copyright (c) 2020 Andrew Hewus Fresh <andrew@afresh1.com>
#
# Permission to use, copy, modify, and distribute this software for any
# purpose with or without fee is hereby granted, provided that the above
# copyright notice and this permission notice appear in all copies.
#
# THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
# WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
# ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
# OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
my ($input, $output);
$input = @ARGV ? shift : '-';
$output = @ARGV ? shift : '-';
open my $usbdevs, '-|', qw< /usr/sbin/usbdevs -v > or die "usbdevs: $!";
open my $dmesg, '-|', qw< dmesg > or die "dmesg: $!";
pledge(qw< rpath wpath cpath >) or die "Unable to pledge: $!";
my $template;
if ( $input eq '-' ) {
open $template, '<&STDIN' or die "Unable to read from STDIN: $!";
}
else {
open $template, '<', $input or die "template: $!";
}
my $remote;
if ( $output eq '-' ) {
open $remote, '>&STDOUT' or die "Unable to dup STDOUT: $!";
}
else {
open $remote, '>', $output or die "remote: $!";
}
pledge or die "Unable to pledge: $!";
my $coms = parse_dmesg( $dmesg, parse_usbdevs($usbdevs) );
for ( readline $template ) {
s/:(iSerial)=([^:]+):/ ':dv=' . lookup($1, $2, $coms) . ':'/ge;
print $remote $_;
}
#use Data::Dumper qw< Dumper >; die Dumper $coms;
sub lookup {
my ($key, $value, $coms) = @_;
return ( grep { $coms->{$_}->{$key} eq $value }
keys %{ $coms } )[0] || '';
}
sub parse_usbdevs {
my ($fh) = @_;
my @devs;
my $dev;
my $controller;
while (readline $fh) {
chomp;
if (/^Controller (\S+):$/) {
$controller = $1;
next;
}
if (s/^(\S+) (\S+)://) {
if ( $1 eq 'addr' ) {
$dev = {
controller => $controller,
addr => $2 + 0,
};
push @devs, $dev;
}
else {
$dev->{$1} = $2;
}
}
next unless exists $dev->{addr};
if (/^\s+driver: (.*)$/) {
$dev->{driver} = $1;
}
else {
s/^\s+|\s+$//g;
for ( split /, / ) {
if (/^(config|rev|iSerial) (.*)$/) {
$dev->{$1} = $2;
}
else {
push @{ $dev->{opts} }, $_;
}
}
}
}
return \@devs;
}
sub parse_dmesg {
my ($fh, $usbdevs) = @_;
my %want = map { $_->{driver} => $_ } @{ $usbdevs };
while (readline $fh) {
if ( /^(\S+) detached\b/ ) {
if ( my $found = $want{$1} ) {
delete $found->{at};
}
}
elsif ( /^(\S+) at (\S+) (.*)$/ ) {
my $at = { dev => $1, extra => $3 };
my $found = $want{$2} ||= {};
push @{ $found->{at} }, $at;
}
}
my %found;
for my $dev ( values %want ) {
for my $at (@{ $dev->{at} || [] }) {
if ( $at->{dev} =~ /^(u)?com(\d+)/ ) {
my $com = sprintf( ( $1 ? "cuaU%d" : "cua%02d" ), $2 );
$found{$com} = $dev;
}
}
}
return \%found;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment