Shallow Thoughts : : linux

Akkana's Musings on Open Source Computing and Technology, Science, and Nature.

Sun, 05 Jul 2020

Q is for Quadraphonic

... which is what I have now on my Carbon X1 gen 7 laptop.

Early reviews of this particular laptop praised its supposedly excellent speakers (as laptops go), but that has never been apparent on Linux.

It is an improvement over the previous version -- the microphone works now, which it didn't in 19.10 -- though in the meantime I acquired a Samson GoPro based on Embedded.fm's recommendation (it works very well).

But although the internal mic works now, the sound from the built-in speakers is just terrible, even worse than it was before. The laptop has four speakers, but Ubuntu is using only two.

Read more ...

Tags: , ,
[ 12:44 Jul 05, 2020    More linux | permalink to this entry | comments ]

Thu, 07 May 2020

PulseAudio from the Command Line

Controlling PulseAudio from the Command Line #tags linux,audio,pulseaudio,ubuntu,cmdline

Controlling PulseAudio via pavucontrol is all very nice, but it's time consuming and fiddly: you have to do a lot of clicking in a lot of tabs any time you want to change anything.

So I've been learning how to control PulseAudio from the command line, so I can make aliases to switch between speakers quickly, or set audio defaults at login time.

That was going to be a blog post, but I think this is going to be an evolving document for quite some time, so instead, I just made it a page on the Linux section of my website: Controlling PulseAudio from the Command Line.

I also wrote a Python script, pulsehelper.py, that uses some of these commands to provide clearer output and easier switching. It even uses color and bold fonts if you have the termcolor module installed. Like the document, this script is likely to be evolving for quite some time.

Happy listening and recording!

Tags: , , ,
[ 12:21 May 07, 2020    More linux | permalink to this entry | comments ]

Mon, 04 May 2020

PulseAudio via GUI: Pavucontrol

(Note: this is not an alphabet post. You may have noticed I'm a little stuck on I. I hope to get un-stuck soon; but first, here are a pair of articles on configuring audio on Linux.)

I'm a very late adopter for PulseAudio. In the past, on my minimal Debian machines, nearly any sound problem could be made better by apt-get remove pulseaudio. But pulse seems like it's working better since those days, and a lot of applications (like Firefox) require it, so it's time to learn how to use it. Especially in these days of COVID-19 and video conferencing, when I'll need to be using the microphone and speakers a lot more. (I'd never actually had a reason to use the microphone on my last laptop.)

Beginner tutorials always start with something like "Go into System Preferences and click on Audio", leaving out anyone who doesn't use the standard desktop. The standard GUI PulseAudio controller is pavucontrol. It has four tabs.

[Configuration tab in pavucontrol]

Read more ...

Tags: , , ,
[ 18:04 May 04, 2020    More linux | permalink to this entry | comments ]

Mon, 30 Mar 2020

D is for Devilish Place Names

It was surprisingly hard to come up with a "D" to write about, without descending into Data geekery (always a temptation). Though you may decide I've done that anyway with today's topic.

Out for a scenic drive to shake off some of the house-bound cobwebs, I got to thinking about how so many places are named after the Devil. California was full of them -- the Devil's Punchbowl, the Devil's Postpile, and so forth -- and nearly every western National Park has at least one devilish feature.

How many are there really? Happily, there's an easy way to answer questions like this: the Geographic Names page on the USGS website, which hosts the Geographic Names Information System (GNIS). You can download entire place name files for a state, or you can search for place name matches at: GNIS Feature Search.

When I searched there for "devil", I got 1883 hits -- but many of them don't actually include the word "Devil". What, are they taking lessons from Google about searching for things that don't actually match the search terms?

I decided I wanted to download the results so I could count them more easily. The page offers View & Print all or Save as pipe "|" delimited file. I chose to save the file.

Read more ...

Tags: , , ,
[ 16:30 Mar 30, 2020    More linux/cmdline | permalink to this entry | comments ]

Sat, 30 Nov 2019

Installing Lenovo Firmware Packaged as a .exe on a Linux Machine

My new Lenovo Carbon X1 Gen 7 has one irritating problem: the trackpad sometimes disappears, flooding dmesg with messages like "i2c_designware i2c_designware.1: controller timed out". Once this happens, the only fix is to reboot.

Lenovo has a fix -- new trackpad firmware -- but unlike their BIOS updates, which are installable from Linux, device firmware updates are distributed as Windows EXE files that require running Windows on the bare metal, leaving Linux users out in the cold. Ironic, since Lenovo is so popular among Linux users and is a member of the Linux Firmware Service, and the CX1 is supposedly Ubuntu certified.

Those Linux users on the forums who managed to install the firmware update raved about it, saying that indeed it solved their problem. But finding a way to to install it led me on a not-so-merry four-day quest.

Here's how I installed the firmware, in the end:

Make a Windows to Go using Rufus on a Real Windows Box

  1. Back up anything you don't want to lose, because you never know.

  2. Borrow a real Windows box. I tried many times using Windows inside VirtualBox and QEmu on top of Linux, but it never worked.
  3. On Windows, install Rufus.

  4. Download the Windows 10 Installer ISO (5 gigabytes, give or take)

  5. Find a USB stick or SD card, 16G or larger. Actually, find a bunch of them: this process is incredibly finicky about the stick you use and the only way you find out is that it doesn't work and you have to try again (see below).

  6. Use Rufus to create a Windows to Go image. The alternative is to make a Windows installer; that won't work, because you can't run anything useful from the installer, and you don't want to actually install Windows, or you wouldn't be in this fix in the first place.

    Be patient: creating a W2G image takes several hours. Click on Rufus' log file button (it's the rightmost of four obscure icons down near the lower left of the Rufus window; it has a mouseover tooltip) at any time to see what's happening; if things don't go right you might at least get some idea why.

  7. When the W2G stick is finished (whew!), move it to your Linux machine and mount its second partition (/dev/sdb2 or whatever). This will tell you it wasn't properly unmounted and it's fixing it, giving you a heart attack about whether Linux is going to change the filesystem in some way that makes it fail after you waited all that time creating it.

  8. Copy the firmware .exe to it. Wherever you want; I just put it at the root of the filesystem. Sync and unmount it.

  9. Boot your computer from the USB stick. This will take forever and may fail if the phase of the moon is wrong.

    If you're lucky and the planets are in alignment, eventually a Windows installer will come up and ask you a bunch of annoying questions about language, keyboard, whether you consent to having Microsoft spy on you in a skillion different ways, name, password, three security questions, etc. Meanwhile, you're having another heart attack because does this mean it's going to install Windows to your real disk on top of Linux? Hopefully not -- at least it didn't in my case -- but here's where you really want to have that recent backup.

  10. If you make it all the way through the questions and get a Windows screen, rejoice! Navigate to wherever you put your exe and run it. Cross your fingers -- maybe you're done!

  11. If it hangs or bluescreens during boot, or Rufus fails to create the W2G stick in the first place, try running Rufus again with a different USB stick. I think I tried five before finally finding one that worked, and the successful one (a Transcend SD card in an old Patriot USB adapter) wasn't the newest, or the fastest, or the largest. It's a mystery.

Some Approaches that Didn't Work

Before I finally got this working, I wasted four days trying many other approaches. Many of them sound very clever and reasonable and ought to work, but they didn't work for me. These include:

So, lots of different ways. Some of them have worked at some time for someone. Also, I never did try Wine. I don't think Wine would be able to run the actual exe and update the trackpad firmware (I was afraid to try it), but it's possible that Rufus in Wine might have been able to make a Windows To Go stick.

If anyone manages that -- or any other way of getting this to work -- I'd love to hear about it.

Tags: ,
[ 20:16 Nov 30, 2019    More linux | permalink to this entry | comments ]

Sun, 24 Nov 2019

Adjusting PulseAudio Volume from the Command-Line (or a Window Manager)

I have a new laptop, a birthday present to myself last month. For once, rather than buying a cut-rate netbook, I decided to treat myself to a fancy Lenovo Carbon X1 with an up-to-date processor and lots of RAM.

Since I have way more resources than I'm used to, I decided I'd try installing a full Ubuntu and not trying to pare it down to a super lightweight system. I'm still running the lightweight, fast, highly configurable Openbox window manager instead of a full Gnome desktop: Openbox does just what I tell it and no more, and doesn't surprise me with random redesigns. But I did let Ubuntu install some system utilities I've always avoided in the past, like NetworkManager and PulseAudio. I decided I'd give them a chance, see if they've gotten better since I last checked.

They have, though they're still a bit of a hassle to deal with. NetworkManager can be controlled through nmcli, which is poorly documented but works okay if you google long enough to find the proper incancations. PulseAudio gave me a bit more trouble.

The standard GUI for controlling PulseAudio is pavucontrol. It showed two audio devices: "USB PnP Audio Device Analog Stereo" and "Built-in Audio Analog Stereo". Turns out the USB PnP option is a sound card built into the USB hub, a Totu tt-hb003a 11-in-1 USB-C hub that lets me connect to a charger, external monitor, SD and micro-SD slots, and extra USB ports without juggling a lot of extra cables.

Pulse assumes -- probably reasonably, though it's wrong in this case -- that if I have a USB audio device connected, I probably want to use it in preference to the laptop's built-in audio. That would make sense if I had external speakers plugged in, but I left all my computer speakers behind when I moved. I should probably order some speakers. But meanwhile, I needed to persuade PulseAudio to ignore the hub and use the laptop's built-in sound system.

Mute/Unmute via the Keyboard

The Lenovo, like most laptops, has a dedicated key for muting, Fn-F1. It even has a little light on it to show whether it's muted. In Openbox, pressing Fn-F1 actually muted the sound, and even turned on the light. This is probably because I'd previously set key="XF86AudioMute" to run amixer set Master toggle in .config/openbox/rc.xml, which worked on my Pulse-free pared-down Debian netbook. The problem is that pressing iFn-F1 again didn't bring the sound back. Instead, it was unmuting the USB hub's audio. Clicking "Set as fallback" on the built-in audio in pavucontrol made no difference.

It turns out that it is virtually impossible to persuade PulseAudio to use "Built-in Audio" when a "USB PnP Audio Device" is available. I finally found the secret: in pavucontrol's Configuration tab, set Profile for the PnP USB device to Off. Now only the built-in device shows up in the other tabs.

But that amixer command still wasn't unmuting properly, so the next step was to find a command that would actually unmute. Someone on #linux suggested pactl set-sink-mute @DEFAULT_SINK@ toggle and that worked great from the command line. But when I tried to bind it in Openbox to the XF86AudioMute key, it did nothing. I still don't understand why not; I wasted a lot of time comparing my shell environment to openbox's environment and never found the difference.

Back to web searching, I found an askbuntu thread suggesting some Openbox stanzas. In particular, it apparently works better to use alsamixer rather than pactl. This finally worked for toggling mute:

    <keybind key="XF86AudioMute">
        <action name="Execute">
            <command>amixer -q -D pulse sset Master toggle</command>
        </action>
    </keybind>

Volume Controls via Function Keys

Partial success! Unfortunately, the volume control commands in that same askbuntu post, amixer -q -D pulse sset Master 3%+ unmute, did nothing. I had already noticed that in pavucontrol, the volume controls didn't work either. In fact, if I started some music playing and then called up alsamixer, channels like Master and Speaker didn't do anything; the only channel that affected volume was ALSA PCM. After some fiddling, I discovered that I had to change Master to PCM and remove the -D pulse:

    <keybind key="XF86AudioRaiseVolume">
      <action name="Execute">
            <command>amixer sset PCM 4%+ unmute</command>
        </action>
    </keybind>
    <keybind key="XF86AudioLowerVolume">
        <action name="Execute">
            <command>amixer sset PCM 4%- unmute</command>
        </action>
    </keybind>

I'm sure I'll eventually need to fiddle some more. For one thing, if I ever want to use audio during a talk (as I did briefly at my Stonehenge talk earlier this year) I'll need to figure out how to enable a temporary HDMI sound sink quickly without needing to fiddle with pavucontrol. But for now, I'm happy to have the basic laptop volume and mute keys working.

Tags: , , ,
[ 15:43 Nov 24, 2019    More linux | permalink to this entry | comments ]

Sun, 03 Nov 2019

Emulating Raspbian on your Linux x86/amd64 System

I was planning to teach a class on Raspberry Pis, and I wanted to start with the standard Raspbian image, update it, and add some programs like GIMP that we'd use in the class. And I wanted to do that just once, before burning the image to a bunch of different SD cards. Is there a way to do that on my regular Linux box, with its nice fast processor and disk?

Why yes, there is, and it's pretty easy. But there are a lot of unclear or misleading tutorials out there, so I hope this is a bit simpler and easier to follow.

I got most of this from a tutorial that no longer seems to be available (but I'll include the link in case it comes back): Solar Staker/RPI Image/Creation.

I've tested this on Ubuntu 19.10, Debian Stretch and Buster; the instructions should be pretty general except for the name of the loopback mount. Commands you type are in bold; the rest is the output you should see. $ is your normal shell prompt and # is a root prompt.

Required Packages

You'll need kpartx, qemu and some supporting packages. On Debian or Ubuntu:

$ sudo apt install kpartx qemu binfmt-support qemu-user-static

You've probably already downloaded a Raspbian SD card image.

Set Up the Loopback Devices

kpartx can read the Raspbian ISO image and split it into the two filesystems it would have if you wrote it to an SD card. It turns the filesystems into loopback devices you can mount like regular filesystems.

$ sudo kpartx -av 2019-09-26-raspbian-buster-lite.img
add map loop10p1 (253:1): 0 524288 linear 7:10 8192
add map loop10p2 (253:2): 0 3858432 linear 7:10 532480

Make a note of those loopback device names. They may not always be loop10p1 and loop10p2, but they'll probably always end in 1 and 2. 1 is the Raspbian /boot filesystem, 2 is the Raspbian root.

(Optional) Check and Possibly Resize the Raspbian Filesystem

Make sure that the Raspbian filesystem is intact, and that it's a reasonable size.

In practice, I didn't find this made any difference (everything was fine to begin with), but it doesn't hurt to make sure.

$ sudo e2fsck -f /dev/mapper/loop10p2
e2fsck 1.45.3 (14-Jul-2019)
Pass 1: Checking inodes, blocks, and sizes
Pass 2: Checking directory structure
Pass 3: Checking directory connectivity
Pass 4: Checking reference counts
Pass 5: Checking group summary information
rootfs: 44367/120720 files (0.3$ non-contiguous), 292014/482304 blocks

$ sudo resize2fs /dev/mapper/loop10p2
resize2fs 1.45.3 (14-Jul-2019)
The filesystem is already 482304 (4k) blocks long.  Nothing to do!

Mount the Loopback Filesystems

You're ready to mount the two filesystems. A Raspbian SD card image contains two filesystems.

Partition 1 is a small vfat /boot filesystem containing the kernel and some other files it needs for booting, plus the two important configuration files cmdline.txt and config.txt.

Partition 2 is the Raspbian root filesystem in ext4 format. The Raspbian root includes an empty /boot directory; mount the root first, then mount the Raspbian boot partition on Raspbian's /boot:

$ sudo mkdir /mnt/pi_image
$ sudo mount /dev/mapper/loop10p2 /mnt/pi_image
$ sudo mount /dev/mapper/loop10p1 /mnt/pi_image/boot

Prepare for Chroot

You're going to chroot to the Raspbian filesystem. Chroot limits the filesystem you can access, so when you type /, instead of your host filesystem's / you'll see the root of the Raspbian filesystem, /mnt/pi_image. That means you won't have access to your host system's /usr/bin, any more.

But qemu needs /usr/bin/qemu-arm-static to be able to emulate ARM binaries in user mode. So copy that to the Raspbian filesystem so you'll still be able to access it after the chroot:

$ sudo cp /usr/bin/qemu-arm-static /mnt/pi_image/usr/bin

Chroot to the Raspbian System

$ sudo chroot /mnt/pi_image /bin/bash
root:/#

Now you're running in Raspbian's root filesystem. All the binaries in your path (e.g. /bin/ls, /bin/bash) are ARM binaries, but if you try to run them, qemu will see qemu-arm-static and run the program as though you're on an actual Raspberry Pi.

Run Stuff!

Now you can run Raspbian commands.

# file /bin/ls
/bin/ls: ELF 32-bit LSB executable, ARM, EABI5 version 1 (SYSV), dynamically linked, interpreter /lib/ld-linux-armhf.so.3, for GNU/Linux 3.2.0, BuildID[sha1]=67a394390830ea3ab4e83b5811c66fea9784ee69, stripped
#
# /bin/ls
bin   dev  home  lost+found  mnt  proc	run   srv  tmp	var
boot  etc  lib	 media	     opt  root	sbin  sys  usr

# file /bin/cat
/bin/cat: ELF 32-bit LSB executable, ARM, EABI5 version 1 (SYSV), dynamically linked, interpreter /lib/ld-linux-armhf.so.3, for GNU/Linux 3.2.0, BuildID[sha1]=2239a192f2f277bd1a4892e39a41eba97266b91f, stripped
#
# cat /etc/issue
Raspbian GNU/Linux 10 \n \l

You can even install packages or update the whole system:

# apt update
Get:1 http://raspbian.raspberrypi.org/raspbian buster InRelease [15.0 kB]
Get:2 http://archive.raspberrypi.org/debian buster InRelease [25.2 kB]
Get:3 http://raspbian.raspberrypi.org/raspbian buster/main armhf Packages [13.0 MB]
Get:4 http://archive.raspberrypi.org/debian buster/main armhf Packages [259 kB]
Fetched 13.3 MB in 20s (652 kB/s)
Reading package lists... Done

# apt dist-upgrade
Reading package lists... Done
Building dependency tree
Reading state information... Done
Calculating upgrade... Done
The following NEW packages will be installed:
  busybox initramfs-tools initramfs-tools-core klibc-utils libklibc linux-base
  pigz
The following packages will be upgraded:
  dhcpcd5 e2fsprogs file firmware-atheros firmware-brcm80211 firmware-libertas
  firmware-misc-nonfree firmware-realtek libcom-err2 libext2fs2 libmagic-mgc
  libmagic1 libraspberrypi-bin libraspberrypi-dev libraspberrypi-doc
  libraspberrypi0 libss2 libssl1.1 libxml2 libxmuu1 openssh-client
  openssh-server openssh-sftp-server openssl raspberrypi-bootloader
  raspberrypi-kernel raspi-config rpi-eeprom rpi-eeprom-images ssh sudo
  wpasupplicant
32 upgraded, 7 newly installed, 0 to remove and 0 not upgraded.
Need to get 133 MB of archives.
After this operation, 3192 kB of additional disk space will be used.
Do you want to continue? [Y/n]

Pretty neat! Although you're not actually running Raspbian, you can run Raspbian executables with the Raspbian root filesystem mounted as though you were actually running on your Raspberry Pi.

Cleaning Up

When you're done with the chroot, just exit that shell (Ctrl-D or exit). If you want to undo everything else afterward:

$ sudo rm /mnt/pi_image/usr/bin/qemu-arm-static

$ sudo umount /mnt/pi_image/boot
$ sudo umount /mnt/pi_image

$ sudo kpartx -dv /dev/loop0
$ sudo losetup -d /dev/loop0

$ sudo rmdir /mnt/pi_image

Limitations

Keep in mind you're not really running Raspbian. You never booted the Raspbian kernel, and you can't test things that depend on Raspbian's init system, like whether networking works, let alone running the Raspbian X desktop or accessing GPIO pins. This is an ARM emulator, not a Raspberry Pi emulator.

More details

If you want to read more about qemu user mode and how it lets you run binaries from other architectures, I recommend these links:

Tags: , ,
[ 16:14 Nov 03, 2019    More linux | permalink to this entry | comments ]

Thu, 31 Oct 2019

Command of the Day: See a Random Command Name and Description

Someone on ##linux was talking about "bro pages", which turns out to be a site that collects random short examples of how to use Linux commands. It reminded me of Command Line Magic, a Twitter account I follow that gives sometimes entertaining or useful command-line snippets.

I hadn't been to that page on the Twitter website in a while (I usually use bitlbee for Twitter), and clicking through some of the tweets on the "Who to follow" accounts took me to someone who'd made a GNU CoreUtils cheat sheet. I didn't really want the printed cheat sheet, but I was interested in the commands used to generate it. The commands involved downloading an HTML page and didn't work any more -- the page was still there but its format has changed -- but that got me to thinking about how it might be fun to generate something that would show me a random command and its description, starting not from coreutils but from the set of all commands I have installed.

I can get a list of commands from the installed man pages in /usr/share/man -- section 1, for basic commands, and section 8, for system-admin commands. (The other sections are for things like library routines, system calls, files etc.)

So I can pick a random man page like this:

ls -1 /usr/share/man/man1/ /usr/share/man/man8 | shuf -n 1
which gives me a filename like xlsfonts.1.gz.

The man pages are troff format, gzipped. You can run zcat on them, but extracting the name and description still isn't entirely trivial. In most cases, it comes right after the .SH NAME line, so you could do something like

zcat $(ls -1 /usr/share/man/man1/* /usr/share/man/man8/* | shuf -n 1) | grep -A1 NAME | tail -1
(the * for the two directories causes ls to list the full pathname, like /usr/share/man/man1/xlsfonts.1.gz, instead of just the filename, xlsfonts.1.gz).

But that doesn't work in every case: sometimes the description is more than one line, or there's a line between the NAME line and the actual description.

A better way is to use apropos (man -k), which already knows how to search through man pages and parse them to extract the command name and description. For that, you need to start with the filename (I'm going to drop those *s from the command since I don't need the full pathname any more) and get rid of everything after the first '.'.

You can do that with sed 's_\.[0-9].*__': it looks for everything starting with a dot (\.) followed by a digit ([0-9] -- sed doesn't understand \d) followed by anything (.*) and replaces all of it with nothing, the empty string.

Here's the full command:

apropos $(ls -1 /usr/share/man/man1/ /usr/share/man/man8 | shuf -n 1 | sed 's_\.[0-9].*__')

Sometimes it will give more than one command: for instance, just now, testing it, it found /usr/share/man/man8/snap.8.gz, pared that down to just snap, and apropos snap found ten different commands. But that's unusual; most of the time you'll just get one or two, and of course you could add another | shuf -n 1 if want to make sure you get only one line.

Update: man -f is a better solution: that will give a single apropos-like description line for only the command picked by the first shuf command.

man -f $(ls -1 /usr/share/man/man1/ /usr/share/man/man8 | shuf -n 1 | sed 's_\.[0-9].*__')

It's kind of a fun way to discover new commands you may not have heard of. I'm going to put it in my .zlogin.

Tags: ,
[ 13:22 Oct 31, 2019    More linux/cmdline | permalink to this entry | comments ]