Paolo Amoroso's Journal

Linux

To code on the Z80-MBC2 and V20-MBC homebrew computers I often transfer text files to and from their CP/M environments.

In one direction I send files from Crostini Linux by dumping them to CP/M, where PIP saves the text to CP/M files. In the opposite direction I run PIP on CP/M to print the files to the screen, where Minicom captures the text and saves it to files on Crostini.

CP/M and Unix have different line break and end of file encodings. In addition, the transfer process may introduce unwanted text. That's why the text files exchanged between the systems need some conversion, to automate which I wrote two short Bash scripts.

The first script, unix2cpm, converts line breaks and the end of file marker in the input to the CP/M encoding and prints the result to stdout. If the optional file name argument isn't supplied the script reads from stdin with a technique I researched. This is the script:

#!/usr/bin/env bash

# Convert line breaks and end of file from Unix to CP/M.
#
# Usage:
#
#   unix2cpm [filename]
#
# Reads from stdin if the optional argument is missing.

input_file="${1:-/dev/stdin}"

cat "$input_file" | unix2dos
echo -e -n '\x1a'

The script calls unix2dos distributed with the dos2unix / unix2dos tools. unix2dos converts line breaks from Unix to MS-DOS, which borrows the encoding from CP/M. unix2cpm needs only to append with echo the ^Z end of file control character.

Once converted, the file is ready to be dumped from Linux to CP/M.

I initiate file transfers in the oppostite direction by executing the Minicom command to capture the terminal output to a file, Ctrl-A L (Capture on/off). Then, at the CP/M prompt, I execute a command like this to print a file to the console:

A>a:pip con:=filename.txt

When printing ends and the A> prompt reappears, I turn off output capture in Minicom to close the capture file. The captured output contains the PIP command in the first line, then the text of the file, and finally the A> prompt in the last line.

To remove the unwanted first and last line I wrote the second script, skipfl (skip first and last). Again, the script reads from stdin if the optional file name isn't supplied and writes to stdout. The code is:

#!/usr/bin/env bash

# Skip the first and last file of the argument file
#
# Usage:
#
#   skipfl [filename]
#
# Reads from stdin if the optional argument is missing.

input_file="${1:-/dev/stdin}"

cat "$input_file" | sed '1d' | sed '$d'

The script calls sed to delete the first and last line with the d command.

No further processing of the captured CP/M output file is necessary as Minicom takes care of inserting the proper line break and end of file encodings.

#z80mbc2 #v20mbc #linux #retrocomputing

Discuss... Email | Reply @amoroso@fosstodon.org

I needed to write some Bash scripts on Linux that read the input from stdin or a file passed as an optional argument, but couldn't figure how.

Googling turned up several designs and examples, such as on StackOverflow, where the script directly processes the input. But I actually wanted the script to assemble a pipeline, feed the input into the beginning, and delegate the processing to the programs and filters in the pipeline.

More googling turned up exactly what I wanted, a reply by the user Daniel buried in a long StackExchange thread.

The trick is to assign to a variable the input stream and feed it into the first program of the pipeline. To demonstrate the technique, the script unlc (unique line count) prints the number of unique lines in the input:

#!/usr/bin/env bash

# unlc - print number of unique lines in the optional input file or stdin
#
# Usage:
#
#   unlc [input-file]

input_file="${1:-/dev/stdin}"

cat "$input_file" | sort | uniq | wc -l

The code assigns to input_file the first argument $1 passed to the script, if supplied, or the standard input. Then cat feeds the content of input_file to the rest of the pipeline. The script is invoked by passing a file as an argument or feeding the data into the script's standard input:

$ cat input-file.txt 
1
2
2
3
4
4
4
4
$ unlc input-file.txt 
4
$ cat input-file.txt | unlc
4

Simple and brilliant.

#Linux

Discuss... Email | Reply @amoroso@fosstodon.org

My post on why I use a Chromebox was shared on Hacker News and got enough upvotes to receive more than 4,000 views over a day. The feedback in the comments made me realize I didn't explain why I use chromeOS instead of Linux, so here goes.

I did use various Linux distros from the mid 1990s until switching to chromeOS, but I got exasperated with maintenance.

Device driver support was suboptimal. System updates would often break something and throw me to the console, forcing to waste days to troubleshoot and fix whatever broke and restore X. These issues were so frequent I ended up deferring to apply system updates, trading features and fixes for stability.

I had enough with Linux maintenance, realized I was living in Chrome anyway, didn't mind Google, and gave chromeOS a try. Seven years and four chromeOS devices later, I never had a single system update issue. And maintenance simply disappeared.

For years I used also Windows and Mac OS X but I liked Linux — and later chromeOS — much more.

#chromeOS #Linux

Discuss... Email | Reply @amoroso@fosstodon.org

Chrome OS 101 was supposed to prompt to upgrade Crostini, its Linux container subsystem, from Debian Buster to Bullseye. A 9to5Google article on Chrome OS 101 noted:

Linux on Chrome OS now uses Debian 11 (Bullseye) with upgrade prompts available in the Settings app for those on Debian 10 (Buster). You also now get an upgrade log that’s saved in the Downloads folder.

However, when Chrome OS Stable 101.0.4951.59 landed on my ASUS Chromebox 3 with Crostini running Buster, I got no such prompt. A comment by the user Mr. Smith on an About Chromebooks post about upgrading to Bullseye clarified the prompt is hidden behind a flag.

I went through the upgrade process Mr. Smith outlined and it worked, sort of. Here are the steps I took:

  1. enable the flag chrome://flags#crostini-bullseye-upgrade
  2. reboot Chrome OS
  3. accept the prompt to upgrade to Bullseye
  4. open the Terminal app
  5. run the following shell commands:

    $ sudo apt update
    $ sudo apt full-upgrade -y
    $ sudo apt -y autoremove
    

Sure enough, after rebooting the system I got the upgrade prompt, accepted it, and watched a dialog reporting on the upgrade progress. A dozen minutes later the process ended with the following errors:

Failed to connect to bus: No data available
Failed to connect to bus: No data available
invoke-rc.d: initscript sudo, action "restart" failed.
Failed to connect to bus: No data available
dpkg: error processing package sudo (--configure):
 installed sudo package post-installation script subprocess returned error exit status 1
Errors were encountered while processing:
 sudo
E: Sub-process /usr/bin/dpkg returned an error code (1)

I'm not sure what triggered the errors. But a few quick checks of Crostini suggested the installed apps work and nothing major seems broken. Therefore, I'm leaving the container upgraded to Bullseye 11.3 as is and monitor it.

#chromeOS #Linux

Discuss... Email | Reply @amoroso@fosstodon.org

Although Linux had been my daily driver for almost two decades, when I switched to Chrome OS I regarded the Crostini Chrome OS Linux container mostly as a curiosity.

Sure, I was eager to have some fun with Linux on my Chromebox. But I already lived fully in the cloud and web apps met all my computing needs. I assumed the main use cases for Crostini were advanced development or DevOps.

To check out Crostini, I installed some astronomical image visualization and processing software for Linux. Next, I used Python preinstalled on Crostini to test the code I was writing with Repl.it and make sure it ran on a different system.

When I began working on Suite8080, a suite of Intel 8080 Assembly cross-development tools in Python, I needed some CP/M emulators and 8080 tools to test the Python programs I was developing, as well as my Assembly code. Again, installing and running such Linux software on Crostini worked well.

I came to love Crostini, now a key component of my Chrome OS toolset. It lets me run all sorts of niche applications and specialized software for my hobby projects and geeky interests.

#chromeOS #Linux

Discuss... Email | Reply @amoroso@fosstodon.org

My work on Suite8080 is making me rediscover the Unix M4 macro processing language.

Suite8080, a suite of Intel 8080 Assembly cross-development tools I'm writing in Python, includes also an assembler. I designed the latter to optionally read from the standard input, a feature that gives for free macro processing via a separate tool like m4. I can feed macro Assembly source to m4 and pipe the expanded output into the assembler.

The M4 language is a good choice thanks to its power and ubiquity on POSIX systems.

However, m4 is an obscure tool with a learning curve made steep by the unintuitive quoting and expansion rules. There are few resources and no books or tutorials. The very few code samples are abstract, short, and formatted with little or no whitespace and indentation, which doesn't help readability.

After extensive online research, I put together a list of the best learning and reference resources:

#Linux #development

Discuss... Email | Reply @amoroso@fosstodon.org