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); }