1 /* 2 * Copyright 2005, Ingo Weinhold, bonefish@users.sf.net. 3 * Distributed under the terms of the MIT License. 4 */ 5 6 #include <errno.h> 7 #include <fcntl.h> 8 #include <stdio.h> 9 #include <stdlib.h> 10 #include <string.h> 11 #include <unistd.h> 12 #include <sys/stat.h> 13 14 #include <ByteOrder.h> 15 #include <Drivers.h> 16 #include <Entry.h> 17 #include <File.h> 18 #include <fs_info.h> 19 #include <Resources.h> 20 #include <TypeConstants.h> 21 22 static const char *kCommandName = "makebootable"; 23 24 static const int kBootCodeSize = 1024; 25 static const int kFirstBootCodePartSize = 512; 26 static const int kSecondBootcodePartOffset = 676; 27 static const int kSecondBootcodePartSize = kBootCodeSize 28 - kSecondBootcodePartOffset; 29 static const int kPartitionOffsetOffset = 506; 30 31 static int kArgc; 32 static const char *const *kArgv; 33 34 // usage 35 const char *kUsage = 36 "Usage: %s [ options ] <file> ...\n" 37 "\n" 38 "Makes the specified BFS partitions/devices bootable by writing boot code\n" 39 "into the first two sectors. It doesn't mark the partition(s) active.\n" 40 "\n" 41 "If a given <file> refers to a directory, the partition/device on which the\n" 42 "directory resides will be made bootable. If it refers to a regular file,\n" 43 "the file is considered a disk image and the boot code will be written to\n" 44 "it.\n" 45 "\n" 46 "Options:\n" 47 " -h, --help - Print this help text and exit.\n" 48 "\n" 49 "[compatibility]\n" 50 " -alert - Compatibility option. Ignored.\n" 51 " -full - Compatibility option. Ignored.\n" 52 " -safe - Compatibility option. Fail when specified.\n" 53 ; 54 55 // print_usage 56 static void 57 print_usage(bool error) 58 { 59 // get command name 60 const char *commandName = NULL; 61 if (kArgc > 0) { 62 if (const char *lastSlash = strchr(kArgv[0], '/')) 63 commandName = lastSlash + 1; 64 else 65 commandName = kArgv[0]; 66 } 67 68 if (!commandName || strlen(commandName) == 0) 69 commandName = kCommandName; 70 71 // print usage 72 fprintf((error ? stderr : stdout), kUsage, commandName, commandName, 73 commandName); 74 } 75 76 // print_usage_and_exit 77 static void 78 print_usage_and_exit(bool error) 79 { 80 print_usage(error); 81 exit(error ? 1 : 0); 82 } 83 84 // write_boot_code_part 85 static void 86 write_boot_code_part(const char *fileName, int fd, const uint8 *bootCodeData, 87 int offset, int size) 88 { 89 printf("writing %d bytes at offset %d\n", size, offset); 90 ssize_t bytesWritten = write_pos(fd, offset, bootCodeData + offset, size); 91 if (bytesWritten != size) { 92 fprintf(stderr, "Error: Failed to write to \"%s\": %s\n", fileName, 93 strerror(bytesWritten < 0 ? errno : B_ERROR)); 94 } 95 } 96 97 // main 98 int 99 main(int argc, const char *const *argv) 100 { 101 kArgc = argc; 102 kArgv = argv; 103 104 if (argc < 2) 105 print_usage_and_exit(true); 106 107 // parameters 108 const char **files = new const char*[argc]; 109 int fileCount = 0; 110 111 // parse arguments 112 for (int argi = 1; argi < argc;) { 113 const char *arg = argv[argi++]; 114 115 if (arg[0] == '-') { 116 if (strcmp(arg, "-h") == 0 || strcmp(arg, "--help") == 0) { 117 print_usage_and_exit(false); 118 } else if (strcmp(arg, "-alert") == 0) { 119 // ignore 120 } else if (strcmp(arg, "-full") == 0) { 121 // ignore 122 } else if (strcmp(arg, "-safe") == 0) { 123 fprintf(stderr, "Error: Sorry, BeOS R3 isnt't supported!\n"); 124 exit(1); 125 } else { 126 print_usage_and_exit(true); 127 } 128 129 } else { 130 files[fileCount++] = arg; 131 } 132 } 133 134 // we need at least one file 135 if (fileCount == 0) 136 print_usage_and_exit(true); 137 138 // open our executable 139 BFile resourcesFile; 140 status_t error = resourcesFile.SetTo(argv[0], B_READ_ONLY); 141 if (error != B_OK) { 142 fprintf(stderr, "Error: Failed to open my resources: %s\n", 143 strerror(error)); 144 exit(1); 145 } 146 147 // open our resources 148 BResources resources; 149 error = resources.SetTo(&resourcesFile); 150 if (error != B_OK) { 151 fprintf(stderr, "Error: Failed to read my resources: %s\n", 152 strerror(error)); 153 exit(1); 154 } 155 156 // read the boot block from the resources 157 size_t resourceSize; 158 const void *resourceData = resources.LoadResource(B_RAW_TYPE, 666, 159 &resourceSize); 160 if (!resourceData) { 161 fprintf(stderr, 162 "Error: Failed to read the boot block from my resources!\n"); 163 exit(1); 164 } 165 166 if (resourceSize != (size_t)kBootCodeSize) { 167 fprintf(stderr, 168 "Error: Something is fishy with my resources! The boot code " 169 "doesn't have the correct size\n"); 170 exit(1); 171 } 172 173 // clone the boot code data, so that we can modify it 174 uint8 *bootCodeData = new uint8[kBootCodeSize]; 175 memcpy(bootCodeData, resourceData, kBootCodeSize); 176 177 // iterate through the files and make them bootable 178 for (int i = 0; i < fileCount; i++) { 179 const char *fileName = files[i]; 180 BEntry entry; 181 error = entry.SetTo(fileName, true); 182 if (error != B_OK) { 183 fprintf(stderr, "Error: Failed to open \"%s\": %s\n", 184 fileName, strerror(error)); 185 exit(1); 186 } 187 188 // get stat to check the type of the file 189 struct stat st; 190 error = entry.GetStat(&st); 191 if (error != B_OK) { 192 fprintf(stderr, "Error: Failed to stat \"%s\": %s\n", 193 fileName, strerror(error)); 194 exit(1); 195 } 196 197 bool noPartition = false; 198 fs_info info; // needs to be here (we use the device name later) 199 if (S_ISDIR(st.st_mode)) { 200 #ifdef __BEOS__ 201 202 // a directory: get the device 203 error = fs_stat_dev(st.st_dev, &info); 204 if (error != B_OK) { 205 fprintf(stderr, "Error: Failed to determine device for " 206 "\"%s\": %s\n", fileName, strerror(error)); 207 exit(1); 208 } 209 210 fileName = info.device_name; 211 212 #else 213 214 (void)info; 215 fprintf(stderr, "Error: Only image files are supported on this " 216 "platform!\n"); 217 exit(1); 218 219 #endif 220 221 } else if (S_ISREG(st.st_mode)) { 222 // a regular file: fine 223 noPartition = true; 224 } else if (S_ISCHR(st.st_mode)) { 225 // a device or partition 226 #ifndef __BEOS__ 227 228 fprintf(stderr, "Error: Only image files are supported on this " 229 "platform!\n"); 230 exit(1); 231 232 #endif 233 } else { 234 fprintf(stderr, "Error: File type of \"%s\" is not unsupported\n", 235 fileName); 236 exit(1); 237 } 238 239 // open the file 240 int fd = open(fileName, O_RDWR); 241 if (fd < 0) { 242 fprintf(stderr, "Error: Failed to open \"%s\": %s\n", fileName, 243 strerror(errno)); 244 exit(1); 245 } 246 247 // get a partition info 248 int64 partitionOffset = 0; 249 250 #ifdef __BEOS__ 251 252 partition_info partitionInfo; 253 if (ioctl(fd, B_GET_PARTITION_INFO, &partitionInfo) == 0) { 254 // hard coded sector size: 512 bytes 255 partitionOffset = partitionInfo.offset / 512; 256 } 257 258 #endif // __BEOS__ 259 260 // adjust the partition offset in the boot code data 261 *(uint32*)(bootCodeData + kPartitionOffsetOffset) 262 = B_HOST_TO_LENDIAN_INT32((uint32)partitionOffset); 263 264 // write the boot code 265 printf("Writing boot code to \"%s\" ...\n", fileName); 266 267 write_boot_code_part(fileName, fd, bootCodeData, 0, 268 kFirstBootCodePartSize); 269 write_boot_code_part(fileName, fd, bootCodeData, 270 kSecondBootcodePartOffset, kSecondBootcodePartSize); 271 272 close(fd); 273 } 274 275 return 0; 276 } 277