From 1f1990506a3a897ed72f354781617c1c10bc9f86 Mon Sep 17 00:00:00 2001 From: James Jones Date: Fri, 2 Jan 2026 16:42:07 -0600 Subject: [PATCH] Accommodate OS-9/68000 releases that accept either the old explicit length and LSN of the bootfile's first segment or the zero length and LSN of the bootfile's file descriptor. Set both LSN possibilities in a semantically meaningful way rather than counting on an accident of how RBF allocates the file descriiptor sector and the first segment in a contiguous hunk. Clarify the condition that os9 gen uses as a contiguity test and why in this context it gives the desired result. Also, use snprintf() with checks for overrun when generating path names for -b and -t, and declare size to be u_int to avoid complaints about &size to _os9_read(). --- os9/os9gen.c | 98 ++++++++++++++++++++++++++++++++++++---------------- 1 file changed, 69 insertions(+), 29 deletions(-) diff --git a/os9/os9gen.c b/os9/os9gen.c index f1c62e4..1766baf 100644 --- a/os9/os9gen.c +++ b/os9/os9gen.c @@ -137,7 +137,20 @@ int os9gen(int argc, char *argv[]) return (ec); } +/* + * OS-9/6809 bootstraps (and some OS-9/68000 bootstraps) require OS9Boot to be + * contiguous so it can be loaded as a single linear stream from the start LSN. + * Later OS-9/68000 systems can instead boot via the OS9Boot file descriptor and + * follow its segment list. + * + * In full generality, contiguity would mean that each segment starts exactly + * where the previous segment ends. ToolShed’s intended usage mirrors the OS-9 + * docs: generate the bootfile on a freshly formatted disk/image. Given that + * OS9Boot is small (well under the per-segment maximum), a practical and + * sufficient check here is that OS9Boot uses only one segment. + */ +#define is_single_segment(fd) (int3((fd).fd_seg[1].lsn) == 0) static int do_os9gen(char **argv, char *device, char *bootfile, char *trackfile, struct personality *hwtype, @@ -146,7 +159,6 @@ static int do_os9gen(char **argv, char *device, char *bootfile, error_code ec = 0; os9_path_id opath; coco_path_id cpath; - int bootfile_LSN = 0, bootfile_Size = 0; char buffer[256]; lsn0_sect LSN0; u_int size; @@ -166,7 +178,12 @@ static int do_os9gen(char **argv, char *device, char *bootfile, /* 1. Open the device raw and read LSB0 */ - sprintf(buffer, "%s,@", device); + ec = snprintf(buffer, sizeof(buffer), "%s,@", device); + if (ec >= sizeof(buffer)) + { + fprintf(stderr, "could not generate raw device pathname\n"); + return (1); + } ec = _os9_open(&opath, buffer, FAM_READ | FAM_WRITE); @@ -311,10 +328,10 @@ static int do_os9gen(char **argv, char *device, char *bootfile, if (bootfile != NULL) { fd_stats fdbuf; - char *bootfileMem; - size = sizeof(fdbuf); + int bootfile_LSN, bootfile_Size, bootfile_Data; + u_int size = sizeof(fdbuf); - /* 1. Open a path to the bootfile */ + /* 2.1. Open a path to the bootfile */ ec = _coco_open(&cpath, bootfile, FAM_READ); @@ -326,46 +343,70 @@ static int do_os9gen(char **argv, char *device, char *bootfile, return (1); } - /* 2.2. Allocate buffer memory and read bootfile */ - bootfileMem = (char *) malloc(65536); /* Allocate maximum */ - if (bootfileMem == NULL) + /* 2.2. Create a file called 'OS9Boot' in the root dir of device */ + ec = snprintf(buffer, sizeof(buffer), "%s,OS9Boot", device); + if (ec >= sizeof(buffer)) { _coco_close(cpath); - fprintf(stderr, "Failed to allocate memory\n"); + fprintf(stderr, "could not generate absolute boot file name\n"); return (-1); } - size = 65536; - _coco_read(cpath, bootfileMem, &size); - - _coco_close(cpath); /* We're done with the path now */ - - /* 2.3. Create a file called 'OS9Boot' in the root dir of device */ - sprintf(buffer, "%s,OS9Boot", device); - - ec = _os9_create(&opath, buffer, FAM_WRITE, - FAM_READ | FAM_WRITE); + ec = _os9_create(&opath, buffer, FAM_WRITE, FAM_READ | FAM_WRITE); if (ec != 0) { - return (ec); + _coco_close(cpath); + fprintf(stderr, "Failed to allocate memory\n"); + return (-1); } - /* 2.4. Write out bootfile to path */ - _os9_write(opath, bootfileMem, &size); - free(bootfileMem); + /* 2.3. Write out bootfile to path */ _os9_gs_fd(opath, sizeof(fdbuf), &fdbuf); - bootfile_LSN = int3(fdbuf.fd_seg[0].lsn); - bootfile_Size = int4(fdbuf.fd_siz); + { + char ioBuf[8192]; + + for (;;) + { + u_int n = sizeof(ioBuf); + + ec = _coco_read(cpath, ioBuf, &n); + if (ec == EOS_EOF) + { + break; + } + if (ec != 0) { + fprintf(stderr, "%s: error %d reading '%s'\n", argv[0], ec, bootfile); + _coco_close(cpath); + _os9_close(opath); + return (1); + } + + ec = _os9_write(opath, ioBuf, &n); + if (ec != 0) + { + fprintf(stderr, "%s: error %d writing OS9Boot\n", argv[0], ec); + _coco_close(cpath); + _os9_close(opath); + return (1); + } + } + } + + _os9_gs_fd(opath, sizeof(fdbuf), &fdbuf); - if (int3(fdbuf.fd_seg[1].lsn) != 0 && extended == 0) + if (!is_single_segment(fdbuf) && extended == 0) { printf("Error: %s is fragmented\n", bootfile); _os9_close(opath); return (1); } + bootfile_Size = int4(fdbuf.fd_siz); + bootfile_LSN = opath->pl_fd_lsn; + bootfile_Data = int3(fdbuf.fd_seg[0].lsn); + _os9_close(opath); /* Link the passed bootfile to LSN0 */ @@ -389,14 +430,13 @@ static int do_os9gen(char **argv, char *device, char *bootfile, return (1); } - if (extended == 0) + if (extended == 0 || (bootfile_Size < 65536 && is_single_segment(fdbuf))) { - _int3(bootfile_LSN, LSN0.dd_bt); + _int3(bootfile_Data, LSN0.dd_bt); _int2(bootfile_Size, LSN0.dd_bsz); } else { - bootfile_LSN--; _int3(bootfile_LSN, LSN0.dd_bt); _int2(0, LSN0.dd_bsz); }