PHP: Run a command and capture STDOUT and STDERR separately

I need to run a shell command in PHP and capture STDOUT and STDERR separately. This function lets you run a command and returns a hash with the various components and outputs.

function run_cmd($cmd) {
    $start   = hrtime(true);
    $cmd     = escapeshellcmd($cmd);
    $process = proc_open($cmd, [
        1 => ['pipe', 'w'], // STDOUT
        2 => ['pipe', 'w'], // STDERR
    ], $pipes);

    if (!is_resource($process)) { return []; }

    $stdout = stream_get_contents($pipes[1]);
    fclose($pipes[1]);
    $stderr = stream_get_contents($pipes[2]);
    fclose($pipes[2]);
    $exit   = proc_close($process);

    $ret = [
        'exit_code' => $exit,
        'stdout'    => trim($stdout),
        'stderr'    => trim($stderr),
        'cmd'       => $cmd,
        'exec_ms'   => (hrtime(true) - $start) / 1000000,
    ];

    return $ret;
}
Leave A Reply

Linux: Disable DNS cache in systemd

New Linux distributions are enabling local DNS caching. For most users this is a sane default, but as a system administrator this can sometimes get in the way. You can check if your local cache is running and see the statistics with:

resolvectl statistics

Which will tell you how active your cache is, what the hit/miss ratio is, and information about DNSSEC. If you need to clear your local cache you can run:

resolvectl flush-caches

Doing this repeatedly can get cumbersome if you are testing remote DNS frequently. If you want to disable local caching all together you can run:

systemctl disable systemd-resolved.service --now

Remember to update your /etc/resolv.conf to point at the correct DNS server after you're done.

Leave A Reply

Using Arduino interrupts to read RPM from a fan

I need to read the RPMs of some 12v PC fans so I wrote up a quick sketch to have an ESP32 monitor and log the RPM for me. You need to use an external interrupt that triggers every time the fan rotates (it triggers 2x per full rotation). I was having crashes before I added the ICACHE_RAM_ATTR parameter to the function. ICACHE_RAM_ATTR tell Arduino to store this function in RAM instead of on the flash. The logic here is that your interrupt function will probably be getting called a lot so it needs to be fast.

Connect the yellow RPM wire from your fan to pin 4, and the ground wire from the fan to the ground of the Arduino. Without the ground wire connected you will now have a shared ground between the Arduino and the fan and the interrupt will not fire.

const uint8_t tachoPin    = 4;
volatile uint32_t counter = 0;

ICACHE_RAM_ATTR void countPulses() {
    counter++;
}

void setup() {
    pinMode(tachoPin, INPUT_PULLUP);
    attachInterrupt(digitalPinToInterrupt(tachoPin), countPulses, FALLING);
    Serial.begin(115200);
}

void loop() {
    delay(1000);
    Serial.printf("%u fan revolutions in the last second\n", counter / 2);

    counter = 0;
}

Note: This code will work on an Arduino Uno without the ICACHE_RAM_ATTR which can be confusing.

Note: Using the internal pull-up resistor on the ESP32 means you can connect the yellow fan wire directly to the MCU. On an Arduino Uno an external pull-up resistor is required.

Leave A Reply

Hashing intgers to get 64bit output

I'm working with a 32bit PRNG and I'd like to get a 64bit integer out of it. You can take two random 32bit integers and combine them into a 64bit one this way:

uint64_t high = rand32();
uint64_t low  = rand32();

uint64_t num64 = (high << 32) | low;

Someone on Reddit suggested using this cool hash to perform a similar task to "upgrade" a 32bit number into a 64bit one by hashing it:

// Borrowed from: https://elixir.bootlin.com/linux/v6.11.5/source/include/linux/hash.h
static inline uint64_t hash64(uint64_t val, unsigned bits) {
        return (val * 0x61c8864680b583ebull) >> (64 - bits);
}
Leave A Reply

Perl: Several ways to generate Unicode

Once you find a Unicode code point you can put it into a Perl string in several ways:

my $thumbs_up = "";

$thumbs_up = "\x{1F44D}";
$thumbs_up = "\N{U+1F44D}";
$thumbs_up = chr(0x1F44D);
$thumbs_up = pack("U", 0x1F44D);

# Make sure STDOUT is set to accept UTF8
binmode(STDOUT, ":utf8");

print $thumbs_up x 2 . "\n";
Leave A Reply

Weird fact of the day

The French author Georges Perec wrote a novel titled A Void without using the letter E. Gilbert Adair translated it into English without using the letter E. Perec wrote a follow up novel, Les revenentes, in which E is the only vowel used.

The Wikipedia summary also excludes the letter E, and it's amazing.

Leave A Reply

Perl: Get file permissions

If you need to see if a file is world readable you'll need to be able to break out file permissions.

my @p     = get_file_permissions("/tmp/foo.txt");
my $other = $p[2];

# 4 = readable, 2 = writeable, 1 = executable
if ($other & 4) { print "File is world readable\n"; }
if ($other & 2) { print "File is world writeable\n"; }
if ($other & 1) { print "File is world executable\n"; }
sub get_file_permissions {
    my $file = shift();

    my @x    = stat($file);
    my $mode = $x[2];

    my $user  = ($mode & 0700) >> 6;
    my $group = ($mode & 0070) >> 3;
    my $other = ($mode & 0007);

    my @ret = ($user, $group, $other);

    return @ret;
}
Leave A Reply

FFmpeg: Measure the average loudness of an audio file

If you need to calculate the average volume or loudness of a file you can use FFmpeg with the volumedetect filter:

ffmpeg -i input.mp3 -af volumedetect -f null /dev/null 2>&1 | grep -P '(mean|max)_volume'

This will report the average (mean) and the maximum volume. This information is useful when comparing two files to see if their "loudness" (or quietness) is comparable.

[Parsed_volumedetect_0 @ 0x698a300] mean_volume: -19.7 dB
[Parsed_volumedetect_0 @ 0x698a300] max_volume: -1.0 dB
Leave A Reply

Meta's AI license is pretty generous

Meta released an update of their Llama AI today and it has a mostly open source license. It's 100% free as long as you have less than "700 million monthly active users in the preceding calendar month". That's cool, but it seems like a pretty arbitrary number. The current world population is 8.1 billion people. As long as no more than 11.5% of the world's population uses your instance of Llama, it's free to you.

Leave A Reply

Perl: UUIDv7

Reddit had a mini challenge about implementing UUIDv7 in various languages. I whipped up a Perl implementation that turned out pretty well. I submitted it to the official GitHub repo and it was accepted.

See also: UUIDv4 in Perl.

Leave A Reply

SSH: Bad server host key: Invalid key length

Newer versions of OpenSSH have deprecated small key sizes for security reasons. We still have some older equipment that uses these types of keys that we need to access. You can work around this with:

ssh -o RSAMinSize=1024 user@domain.com
Leave A Reply

Perl: Matching multiple patterns with a regex

Perl has regular expressions built in to the core of the language and they are very powerful. It's easy enough to find a single match with a regexp:

# Find the *first* three letter word in the string
my $str = "one two three four five six seven eight nine ten";
my @x   = $str =~ m/\b(\w{3})\b/; # ("one")

If you want to find all of the three letter words you can add the g modifier to the end of your regex to tell it to match "globally".

# Find *all* the three letter words
my $str = "one two three four five six seven eight nine ten";
my @x   = $str =~ m/\b(\w{3})\b/g; # ("one", "two", "six", "ten")

You can also iterate on your global regexp if you want to get the matches one at a time:

my $str = "one two three four five six seven eight nine ten";
my @x   = ();
while ($str =~ m/\b(\w{3})\b/g) {
    push(@x, $1);
}

print join(",", @x); # "one,two,six,ten"
Leave A Reply

PHP: Disable PrivateTmp

Rocky Linux uses PrivateTmp to give each process it's own walled off section of /tmp/. This is good for security sometimes, but it can also lead to frustration because files written to /tmp/ or /var/tmp/ will not show up when you need to debug. To disable PrivateTmp for php-fpm you need to modify the systemd configuration for php-fpm. This is done by running systemctl edit php-fpm and adding a section that says:

[Service]
PrivateTmp=false

Once the change is in place you will need to systemctl daemon-reload and then restart systemctl restart php-fpm.

Note: Borrowed from Stack Overflow.

Leave A Reply

Kea DHCP4 systemd file

I'm using Kea as a DHCP server and I need the service to start on boot. I'm not sure why it doesn't ship with a systemd .service file. Here is the file I ended up using:

# Put this in /etc/systemd/system/kea-dhcp4.service
# Reload systemd so it picks it up `systemctl daemon-reload`
# Enable it on boot: `systemctl enable kea-dhcp4`

[Unit]
Description=ISC KEA IPv4 DHCP daemon
Documentation=man:kea-dhcp4(8)
Wants=network-online.target mariadb.service
Requires=kea-ctrl-agent.service
After=network-online.target mariadb.service mysql.service

[Service]
ExecStart=/usr/sbin/kea-dhcp4 -c /etc/kea/kea-dhcp4.conf

[Install]
WantedBy=multi-user.target

This is borrowed from Skywalker-11.

Leave A Reply

Basic snmpd.conf file to monitor ethernet ports of a Linux box

I need to monitor the Ethernet interfaces of a Linux VM. This is the perfect job for snmpd which you can get by installing net-snmp and then applying a basic config. Here is a simplified config that will get you basic read-only access for a community and subnet.

# /etc/snmp/snmpd.conf
rocommunity snmp-read 165.92.231.0/24
rocommunity snmp-read 10.3.1.0/24
rocommunity snmp-read localhost
syslocation "City, State"
syscontact  "Admin <user@domain.com>"

You can test your new SNMP configuration with snmpwalk

snmpwalk -v 2c -c snmp-read 127.0.0.1
Leave A Reply