The main reason that this went unnoticed on my side is that I am slow in upgrading my distro to a newer version, so I was using older cpmtools package version for a while. And probably not many people use custom diskdefs...
Anyhow, thank you very much for the analysis and workaround solution, I would not have figured it out on my own that fast. I did not know about transition to libdsk, although I am familiar with the library and used it in other contexts. I am leaving for work soon, but I will check this on my side later in the day. --- --------------------------- From: "Jacob Nevins" To: "Zarko Zivanov" Cc: "undefined" <1079...@bugs.debian.org> Sent: Monday, August 26, 2024 3:56 AM Subject: Re: Bug#1079619: cpmtools package produces garbage output with cpmls > [Zarko Zivanov:] >> I have previously used cpmtools_2.20 and had no problems. With the >> recent version from repository, I am getting garbage printed on >> screen when I try to list the contents of an IMG file (or, actually, >> many IMG files, this one is just an example). I wrote: > I think the significant difference is probably that between 2.20-2 and > 2.23-1, Debian's package started to be built against libdsk. (Really, 2.23-3.) OK, I think I know what's going on. (Sorry, this is a bit of a braindump.) I think the main fix is going to have to be in upstream libdsk -- I think it's a misfiring heuristic there -- but I don't have a complete strategy yet. If I look at your image contents with "fsed.cpm -f tim011 demo.img" with my LibDsk build of cpmtools (which should be similar to Debian's), I can see that the tracks are misnumbered compared to my plain build -- what ought to be odd-numbered tracks (1, 3, etc) end up together as track 80+, with the first tracks displayed being what ought to be track 0, 2, 4, ... So the CP/M directory ends up in the wrong place (diskdefs tells cpmtools it should be at the start of track 2), and cpmls shows garbage. Vanilla cpmtools doesn't really have a notion of heads or sidedness -- to it, this disc image is a consecutive set of 160 tracks in ascending order 0..159, without worrying about the relationship of track number to (cylinder, head). libdsk has a more sophisticated notion of heads/sidedness, and supports image formats where tracks aren't ordered in the obvious way, and has various heuristics to determine disc geometry from image file contents, so there's more to go wrong. Using libdsk's 'dskid' tool (which in Debian lives in the libdsk-utils package) on your image to see what libdsk guesses about its geometry in the absence of cpmtools' diskdefs, I can see libdsk has got an idea of the geometry from somewhere which is utter nonsense ("Heads: 128" etc): $ dskid demo.img demo.img: Driver: Raw file driver (alternate sides) Sidedness: OutOut Cylinders: 110 Heads: 128 Sectors: 49 First sector: 1 Sector size: 32768 Data rate: SD Record mode: MFM Complement: No R/W gap: 0x2a Format gap: 0x52 Drive status: 0x28 In particular, I think the "Sidedness: OutOut" in libdsk's garbage geometry is causing our trouble -- that will cause the tracks to be reordered. Within cpmtools, the libdsk driver can cross-check this auto-detected geometry with what diskdefs says, and correctly rejects this as garbage. However, it isn't careful enough to discard all fields from the garbage geometry; in particular, "Sidedness" leaks through. (cpmtools device_libdsk.c:Device_setGeometry()) So where did the nonsense come from? In the absence of clues about geometry from the disc image format (of which there aren't any with a raw disc image like this, for which libdsk correctly auto-selects its 'raw' driver), libdsk tries to infer clues from the (presumed) boot sector at the start of the disc image. Reading the libdsk source, what I think is happening is that libdsk is misdetecting this image as having the boot sector of an "Opus Discovery" (libdsk lib/dskgeom.c:dg_opusgeom()). That has very weak magic -- it just checks whether the first byte is 0x18, and if it is, then it reads geometry out of nearby bytes, without any sanity checking. The result matches the garbage we see from 'dskid'. And indeed the first byte of your disc image is 0x18 ("Z80 relative jump", so hardly unlikely to show up in an unrelated Z80 machine's boot sector). So what needs to happen is: - libdsk's dg_opusgeom() needs to get more discriminating, at the very least, so it doesn't misfire on disc images like yours (but I don't know enough about the Opus Discovery to speculate how); - maybe libdsk could usefully learn about TIM 011 boot sectors specifically, especially if they have geometry information embedded in them. (Again, I know nothing about these; do you know of docs/ people who might know more? Ideally English-language, but understand if not.) But this isn't strictly necessary; if none of the boot sector heuristics misfire, libdsk's dsk_defgetgeom() should return an inoffensive default geometry that doesn't cause trouble. - probably cpmtools' device_libdsk.c:Device_setGeometry() needs to be more thorough about sanitising DSK_GEOMETRY if it decides the autodetected geometry was garbage. Workarounds: One workaround which gets your image working with my libdsk-built cpmtools is to add "-T rawoo" to the command-line. This is a fragile bodge, though; it compensates "Sidedness: OutOut" at a different layer rather than reversing it, and it might not stay working with different disc images or libdsk versions. Here's a less fragile workaround, which prevents the misfiring heuristic running at all, by providing the libdsk layer with information about your disc format (yes this does duplicate what's already in diskdefs to some extent): 1. Define a custom libdsk format, either in ~/.libdskrc or... some system-wide location I haven't checked, probably /usr/share somewhere. Here's a minimal one that works for me (it could have more parameters, and some of it is based on guesses/web searches about the TIM 011, caveat emptor); the format is described in the doc/ subdirectory of the libdsk source distribution: [tim011] Sides = Alt Cylinders = 80 Heads = 2 Sectors = 5 SecBase = 17 SecSize = 1024 2. Tell cpmtools to use that format -- you can either use a command-line option "-T raw,tim011" (which forces use of the 'raw' driver with your new 'tim011' format), or add "libdsk:format tim011" to your diskdefs entry (which leaves libdsk free to select a driver, but it'll probably correctly choose 'raw'). Putting this down for now, but if no-one else jumps in, I'll make libdsk upstream aware of this bug report, and we'll see what they have to say. (Full disclosure: I've been testing with my own builds of cpmtools -- 2.23 -- and libdsk -- 1.5.19, rather than the Debian versions. Based on what I've found, I think my conclusions transfer, however.)