/* * * (c) 2004 Laurent Vivier * */ #include #include #include #include #include #include #include #include #include "libmap.h" #include "libemile.h" #include "device.h" int verbose = 0; extern void scanbus(void); extern void diskinfo(char*); enum { ACTION_NONE = 0x00, ACTION_FLAGS = 0x01, ACTION_TYPE = 0x02, ACTION_STARTUP = 0x04, ACTION_SCANBUS = 0x08, ACTION_GET = 0x10, ACTION_PUT = 0x20, }; enum { ARG_NONE = 0, ARG_SCANBUS, ARG_HELP = 'h', ARG_FLAGS = 'f', ARG_TYPE ='t', ARG_STARTUP ='s', ARG_VERBOSE = 'v', ARG_GET = 'g', ARG_PUT = 'p', }; static struct option long_options[] = { {"help", 0, NULL, ARG_HELP }, {"flags", 1, NULL, ARG_FLAGS }, {"type", 1, NULL, ARG_TYPE }, {"startup", 0, NULL, ARG_STARTUP }, {"scanbus", 0, NULL, ARG_SCANBUS }, {"verbose", 0, NULL, ARG_VERBOSE }, {"get-driver", 1, NULL, ARG_GET }, {"put-driver", 1, NULL, ARG_PUT }, {NULL, 0, NULL, 0 }, }; static void usage(int argc, char** argv) { fprintf(stderr, "Usage: %s [--verbose|-v] [--scanbus|]\n", argv[0]); fprintf(stderr, "Usage: %s [--startup|--flags FLAGS][--type TYPE][--get-driver|-g FILE][--put-driver|-p FILE] [| ]\n", argv[0]); fprintf(stderr, "\nbuild: \n%s\n", SIGNATURE); } static int get_driver(map_t *map, int partition, char* appledriver) { int driver; int block_size, block_count; int driver_number; int block, size, type, part; int partition_base, partition_size; int bootstart, bootsize, bootaddr, bootentry, checksum; char processor[16]; unsigned char *code; int fd; int ret; map_read(map, partition); if (strncmp(map_get_partition_type(map), "Apple_Driver", strlen("Apple_Driver")) != 0) { fprintf(stderr, "ERROR: the type of the partition must begin with \"Apple_Driver\"\n"); return -1; } if (strcmp(map_get_partition_name(map), "Macintosh") != 0) { fprintf(stderr, "ERROR: the name of the partition must be \"Macintosh\"\n"); return -1; } map_geometry(map, &block_size, &block_count); printf("block size: %d\n", block_size); map_get_partition_geometry(map, &partition_base, &partition_size); printf("partition base: %d, size %d\n", partition_base, partition_size); driver_number = map_get_driver_number(map); if (driver_number == 0) { fprintf(stderr, "ERROR: no driver on this device\n"); return -1; } for (driver = 0; driver < driver_number; driver++) { map_get_driver_info(map, driver, &block, &size, &type); part = map_seek_driver_partition(map, block * block_size / 512 ); if (part == partition) { map_read(map, part); if (emile_is_apple_driver(map)) break; } part = map_seek_driver_partition(map, block); if (part == partition) { map_read(map, part); if (emile_is_apple_driver(map)) break; } } if (part != partition) { fprintf(stderr, "ERROR: cannot find partition in driver table\n"); return -1; } printf("Found driver %d for partition %d\n", driver, partition + 1); printf("base: %d size: %d type: %d\n", block * block_size / 512, size * block_size / 512 , type); map_get_bootinfo(map, &bootstart, &bootsize, &bootaddr, &bootentry, &checksum, processor); printf("Bootstart: %d, Bootsize: %d, Bootaddr: %d, Bootentry: %d\n", bootstart, bootsize, bootaddr, bootentry); printf("Checksum: 0x%04x, Processor: %s\n", checksum, processor); if (strcmp(processor, "68000") != 0) { fprintf( stderr, "ERROR: cannot manage processor %s (not 68000)\n", processor); return -1; } code = (unsigned char*)malloc(partition_size * 512); if (code == NULL) { fprintf(stderr, "ERROR: cannot malloc() to load driver in memory\n"); return -1; } ret = map_read_sector(map, block * block_size, (char*)code, bootsize); if (ret == -1) { fprintf(stderr, "ERROR: cannot read driver (read())\n"); free(code); return -1; } ret = emile_checksum(code, bootsize); if (ret != checksum) fprintf(stderr, "WARNING: checksum is invalid (0x%x)\n", ret); else printf("Checksum OK\n"); fd = open(appledriver, O_WRONLY | O_CREAT | O_EXCL, S_IWUSR | S_IRUSR); if (fd == -1) { fprintf(stderr, "ERROR: cannot open %s to save driver\n", appledriver); free(code); return -1; } ret = write(fd, code, bootsize); close(fd); free(code); if (ret != bootsize) { fprintf(stderr, "ERROR: cannot save driver to %s\n", appledriver); return -1; } return 0; } static int put_driver(map_t *map, int partition, char* appledriver) { int block_size, block_count; int fd; int ret; unsigned char* code; struct stat st; int driver_number; int block, count, checksum; map_read(map, partition); if (strncmp(map_get_partition_type(map), "Apple_Driver", strlen("Apple_Driver")) != 0) { fprintf(stderr, "ERROR: the type of the partition must begin with \"Apple_Driver\"\n"); return -1; } if (strcmp(map_get_partition_name(map), "Macintosh") != 0) { fprintf(stderr, "ERROR: the name of the partition must be \"Macintosh\"\n"); return -1; } map_geometry(map, &block_size, &block_count); /* read driver from file */ fd = open(appledriver, O_RDONLY); if (fd == -1) { fprintf(stderr, "ERROR: cannot open file %s\n", appledriver); return -1; } ret = fstat(fd, &st); if (ret == -1) { fprintf(stderr, "ERROR: cannot stat file %s\n", appledriver); return -1; } code = malloc(st.st_size); if (code == NULL) { fprintf(stderr, "ERROR: cannot malloc %ld\n", st.st_size); return -1; } ret = read(fd, code, st.st_size); close(fd); if (ret != st.st_size) { fprintf(stderr, "ERROR: cannot read file %s\n", appledriver); return -1; } /* compute driver checksum */ checksum = emile_checksum(code, st.st_size); printf("Driver checksum: 0x%x\n", checksum); /* write file in partition */ ret = map_write_sector(map, block * block_size, (char*)code, st.st_size); free(code); if (ret == -1) { fprintf(stderr, "ERROR: cannot write driver (write())\n"); return -1; } /* set bootinfo */ map_set_bootinfo(map, 0, st.st_size, 0, 0, checksum, "68000"); map_partition_set_flags(map, 0x17F); /* add driver in drivers list */ driver_number = map_get_driver_number(map); if (driver_number == -1) { fprintf(stderr, "ERROR: cannot read drivers number\n"); return -1; } ret = map_get_partition_geometry(map, &block, &count); if (ret == -1) { fprintf(stderr, "ERROR: cannot read partition geometry\n"); return -1; } ret = map_set_driver_info(map, driver_number, block / (block_size / 512) , count / (block_size / 512), 1); if (ret == -1) { fprintf(stderr, "ERROR: cannot set driver info\n"); return -1; } ret = map_set_driver_number(map, driver_number + 1); if (driver_number == -1) { fprintf(stderr, "ERROR: cannot set drivers number\n"); return -1; } ret = map_write(map, partition); if (ret != partition) { fprintf(stderr, "ERROR: cannot set partition information\n"); return -1; } ret = map_block0_write(map); if (ret == -1) { fprintf(stderr, "ERROR: cannot set drivers information\n"); return -1; } return 0; } int main(int argc, char** argv) { map_t *map; int ret; int disk; int partition = 0; char *disk_name; char buffer[16]; int driver; int action = ACTION_NONE; char *dev_name = NULL; char *appledriver = NULL; int c; int option_index; int flags; char *type; device_io_t device; while(1) { c = getopt_long(argc, argv, "hvg:p:sf:t:", long_options, &option_index); if (c == -1) break; switch(c) { case ARG_VERBOSE: verbose++; break; case ARG_HELP: usage(argc, argv); return 0; case ARG_FLAGS: action |= ACTION_FLAGS; flags = strtol(optarg, NULL, 0); break; case ARG_TYPE: action |= ACTION_TYPE; type = optarg; break; case ARG_STARTUP: action |= ACTION_STARTUP; break; case ARG_SCANBUS: action |= ACTION_SCANBUS; break; case ARG_GET: action |= ACTION_GET; appledriver = optarg; break; case ARG_PUT: action |= ACTION_PUT; appledriver = optarg; break; } } if (optind < argc) dev_name = argv[optind++]; if (optind < argc) { partition = strtol(argv[optind++], NULL, 0); if (partition == 0) { fprintf(stderr, "ERROR: partition number cannot be 0 !\n"); return 1; } } if ( !action && dev_name) { diskinfo(dev_name); return 0; } if (action & ACTION_SCANBUS) { if (action & ~ACTION_SCANBUS) { fprintf(stderr, "ERROR: \"--scanbus\" cannot be used with other arguments\n"); return 1; } scanbus(); return 0; } if ((action & ACTION_GET) && (action & ACTION_PUT)) { fprintf(stderr, "You should use --get-driver OR --put-driver\n"); return 1; } if (dev_name == NULL) { fprintf(stderr, "ERROR: you must specify a device\n"); return 1; } if (partition == 0) ret = emile_scsi_get_rdev(dev_name, &driver, &disk, &partition); else ret = emile_scsi_get_rdev(dev_name, &driver, &disk, NULL); if ( (ret == -1) && (optind < argc)) { disk_name = dev_name; driver = 0; disk = 0; partition = atoi(argv[optind++]); } else if (ret == -1) { fprintf(stderr, "ERROR: cannot find disk of %s\n", dev_name); return 1; } else { emile_get_dev_name(buffer, driver, disk, 0); disk_name = buffer; } if (partition == 0) { fprintf(stderr, "ERROR: you must provide device of a partition\n"); return 1; } device_sector_size = 512; device.write_sector = (stream_read_sector_t)device_write_sector; device.read_sector = (stream_read_sector_t)device_read_sector; device.close = (stream_close_t)device_close; device.get_blocksize = (stream_get_blocksize_t)device_get_blocksize; device.data = (void*)device_open(disk_name, O_RDONLY); map = map_open(&device); if (map == NULL) { fprintf(stderr, "ERROR: cannot open partition map\n"); return 4; } if (action & ACTION_STARTUP) { if (action & ~ACTION_STARTUP) { fprintf(stderr, "ERROR: don't use --startup with other flags\n"); return 2; } ret = map_set_startup(map, partition - 1); if (ret == -1) return 3; } if (action & ACTION_GET) { if (appledriver == NULL) { fprintf(stderr, "ERROR: filename missing\n"); map_close(map); return 6; } ret = get_driver(map, partition - 1, appledriver); if (ret == -1) { fprintf(stderr, "ERROR: cannot put driver from partition %d to file %s\n", partition, appledriver); map_close(map); return 6; } map_close(map); return 0; } if (action & ACTION_PUT) { if (appledriver == NULL) { fprintf(stderr, "ERROR: filename missing\n"); map_close(map); return 6; } ret = put_driver(map, partition - 1, appledriver); if (ret == -1) { fprintf(stderr, "ERROR: cannot put driver to partition %d from file %s\n", partition, appledriver); map_close(map); return 6; } map_close(map); return 0; } ret = map_read(map, partition - 1); if (ret != partition - 1) { fprintf(stderr, "ERROR: cannot read partition %d info\n", partition); return 5; } if (action & ACTION_FLAGS) { map_partition_set_flags(map, flags); } if (action & ACTION_TYPE) { ret = map_set_partition_type(map, type); if (ret == -1) { fprintf(stderr, "ERROR: cannot set partition type to %s\n", type); return 7; } } ret = map_write(map, partition - 1); if (ret != partition - 1) { fprintf(stderr, "ERROR: cannot write partition %d info\n", partition); return 8; } map_close(map); return 0; }