void MountVolume::ArgvReceived(int32 argc, char** argv) { MountVisitor mountVisitor; PrintPartitionsVisitor printPartitionsVisitor; bool listAllDevices = false; if (argc < 2) printPartitionsVisitor.listMountablePartitions = true; // parse arguments for (int argi = 1; argi < argc; argi++) { const char* arg = argv[argi]; if (arg[0] != '\0' && arg[0] != '-') { mountVisitor.toMount.insert(arg); } else if (strcmp(arg, "-s") == 0) { mountVisitor.silent = true; } else if (strcmp(arg, "-h") == 0 || strcmp(arg, "--help") == 0) { print_usage_and_exit(false); } else if (strcmp(arg, "-all") == 0) { mountVisitor.mountAll = true; } else if (strcmp(arg, "-allbfs") == 0) { mountVisitor.mountBFS = true; } else if (strcmp(arg, "-allhfs") == 0) { mountVisitor.mountHFS = true; } else if (strcmp(arg, "-alldos") == 0) { mountVisitor.mountDOS = true; } else if (strcmp(arg, "-ro") == 0 || strcmp(arg, "-readonly") == 0) { mountVisitor.readOnly = true; } else if (strcmp(arg, "-u") == 0 || strcmp(arg, "-unmount") == 0) { argi++; if (argi >= argc) print_usage_and_exit(true); mountVisitor.toUnmount.insert(argv[argi]); } else if (strcmp(arg, "-p") == 0 || strcmp(arg, "-l") == 0) { printPartitionsVisitor.listMountablePartitions = true; } else if (strcmp(arg, "-lh") == 0) { printPartitionsVisitor.listAllPartitions = true; } else if (strcmp(arg, "-dd") == 0) { listAllDevices = true; } else if (strcmp(arg, "-r") == 0 || strcmp(arg, "-publishall") == 0 || strcmp(arg, "-publishbfs") == 0 || strcmp(arg, "-publishhfs") == 0 || strcmp(arg, "-publishdos") == 0) { // obsolete: ignore } else print_usage_and_exit(true); } // get a disk device list BDiskDeviceList deviceList; status_t error = deviceList.Fetch(); if (error != B_OK) { fprintf(stderr, "Failed to get the list of disk devices: %s", strerror(error)); exit(1); } // mount/unmount volumes deviceList.VisitEachMountablePartition(&mountVisitor); BDiskDeviceRoster roster; // try mount file images for (StringSet::iterator iterator = mountVisitor.toMount.begin(); iterator != mountVisitor.toMount.end();) { const char* name = (*iterator).c_str(); iterator++; BEntry entry(name, true); if (!entry.Exists()) continue; // TODO: improve error messages BPath path; if (entry.GetPath(&path) != B_OK) continue; partition_id id = -1; BDiskDevice device; BPartition* partition; if (!strncmp(path.Path(), "/dev/", 5)) { // seems to be a device path if (roster.GetPartitionForPath(path.Path(), &device, &partition) != B_OK) continue; } else { // a file with this name exists, so try to mount it id = roster.RegisterFileDevice(path.Path()); if (id < 0) continue; if (roster.GetPartitionWithID(id, &device, &partition) != B_OK) { roster.UnregisterFileDevice(id); continue; } } status_t status = partition->Mount(NULL, mountVisitor.readOnly ? B_MOUNT_READ_ONLY : 0); if (!mountVisitor.silent) { if (status >= B_OK) { BPath mountPoint; partition->GetMountPoint(&mountPoint); printf("%s \"%s\" mounted successfully at \"%s\".\n", id < 0 ? "Device" : "Image", name, mountPoint.Path()); } } if (status >= B_OK) { // remove from list mountVisitor.toMount.erase(name); } else if (id >= 0) roster.UnregisterFileDevice(id); } // TODO: support unmounting images by path! // print errors for the volumes to mount/unmount, that weren't found if (!mountVisitor.silent) { for (StringSet::iterator it = mountVisitor.toMount.begin(); it != mountVisitor.toMount.end(); it++) { fprintf(stderr, "Failed to mount volume `%s': Volume not found.\n", (*it).c_str()); } for (StringSet::iterator it = mountVisitor.toUnmount.begin(); it != mountVisitor.toUnmount.end(); it++) { fprintf(stderr, "Failed to unmount volume `%s': Volume not " "found.\n", (*it).c_str()); } } // update the disk device list error = deviceList.Fetch(); if (error != B_OK) { fprintf(stderr, "Failed to update the list of disk devices: %s", strerror(error)); exit(1); } // print information if (listAllDevices) { // TODO } // determine width of the terminal in order to shrink the columns if needed if (isatty(STDOUT_FILENO)) { winsize size; if (ioctl(STDOUT_FILENO, TIOCGWINSZ, &size, sizeof(winsize)) == 0) { if (size.ws_col < 95) { sVolumeNameWidth -= (95 - size.ws_col) / 2; sFSNameWidth -= (95 - size.ws_col) / 2; } } } if (printPartitionsVisitor.IsUsed()) { printf("%-*s %-*s Size Mounted At (Device)\n", sVolumeNameWidth, "Volume", sFSNameWidth, "File System"); BString separator; separator.SetTo('-', sVolumeNameWidth + sFSNameWidth + 35); puts(separator.String()); if (printPartitionsVisitor.listAllPartitions) deviceList.VisitEachPartition(&printPartitionsVisitor); else deviceList.VisitEachMountablePartition(&printPartitionsVisitor); } exit(0); }
int main(int argc, char** argv) { const struct option kLongOptions[] = { { "help", 0, NULL, 'h' }, { "check-only", 0, NULL, 'c' }, { NULL, 0, NULL, 0 } }; const char* kShortOptions = "hc"; // parse argument list bool checkOnly = false; while (true) { int nextOption = getopt_long(argc, argv, kShortOptions, kLongOptions, NULL); if (nextOption == -1) break; switch (nextOption) { case 'h': // --help usage(stdout); return 0; case 'c': // --check-only checkOnly = true; break; default: // everything else usage(stderr); return 1; } } // the device name should be the only non-option element if (optind != argc - 1) { usage(stderr); return 1; } const char* path = argv[optind]; //UnregisterFileDevice unregisterFileDevice; BDiskDeviceRoster roster; BPartition* partition; BDiskDevice device; status_t status = roster.GetPartitionForPath(path, &device, &partition); if (status != B_OK) { if (strncmp(path, "/dev", 4)) { // try mounted volume status = roster.FindPartitionByMountPoint(path, &device, &partition) ? B_OK : B_BAD_VALUE; } // TODO: try to register file device if (status != B_OK) { fprintf(stderr, "%s: Failed to get disk device for path \"%s\": " "%s\n", kProgramName, path, strerror(status)); return 1; } } // Prepare the device for modifications status = device.PrepareModifications(); if (status != B_OK) { fprintf(stderr, "%s: Could not prepare the device for modifications: " "%s\n", kProgramName, strerror(status)); return 1; } // Check if the partition supports repairing bool canRepairWhileMounted; bool canRepair = partition->CanRepair(checkOnly, &canRepairWhileMounted); if (!canRepair && !canRepairWhileMounted) { fprintf(stderr, "%s: The disk system does not support repairing.\n", kProgramName); return 1; } if (partition->IsMounted() && !canRepairWhileMounted) { fprintf(stderr, "%s: The disk system does not support repairing a " "mounted volume.\n", kProgramName); return 1; } if (!partition->IsMounted() && !canRepair) { fprintf(stderr, "%s: The disk system does not support repairing a " "volume that is not mounted.\n", kProgramName); return 1; } BDiskSystem diskSystem; status = partition->GetDiskSystem(&diskSystem); if (status != B_OK) { fprintf(stderr, "%s: Failed to get disk system for partition: %s\n", kProgramName, strerror(status)); return 1; } // Repair the volume status = partition->Repair(checkOnly); if (status != B_OK) { fprintf(stderr, "%s: Repairing failed: %s\n", kProgramName, strerror(status)); return 1; } status = device.CommitModifications(); return 0; }
// main int main(int argc, const char *const *argv) { kArgc = argc; kArgv = argv; if (argc < 2) print_usage_and_exit(true); // parameters const char **files = new const char*[argc]; int fileCount = 0; bool dryRun = false; off_t startOffset = 0; // parse arguments for (int argi = 1; argi < argc;) { const char *arg = argv[argi++]; if (arg[0] == '-') { if (strcmp(arg, "-h") == 0 || strcmp(arg, "--help") == 0) { print_usage_and_exit(false); } else if (strcmp(arg, "--dry-run") == 0) { dryRun = true; } else if (strcmp(arg, "-alert") == 0) { // ignore } else if (strcmp(arg, "-full") == 0) { // ignore } else if (strcmp(arg, "--start-offset") == 0) { if (argi >= argc) print_usage_and_exit(true); startOffset = strtoll(argv[argi++], NULL, 0); } else if (strcmp(arg, "-safe") == 0) { fprintf(stderr, "Error: Sorry, BeOS R3 isn't supported!\n"); exit(1); } else { print_usage_and_exit(true); } } else { files[fileCount++] = arg; } } // we need at least one file if (fileCount == 0) print_usage_and_exit(true); // read the boot code uint8 *bootCodeData = NULL; #ifndef __ANTARES__ bootCodeData = read_boot_code_data(argv[0]); #else image_info info; if (find_own_image(&info) == B_OK) bootCodeData = read_boot_code_data(info.name); #endif if (!bootCodeData) { fprintf(stderr, "Error: Failed to read \n"); exit(1); } // iterate through the files and make them bootable status_t error; for (int i = 0; i < fileCount; i++) { const char *fileName = files[i]; BEntry entry; error = entry.SetTo(fileName, true); if (error != B_OK) { fprintf(stderr, "Error: Failed to open \"%s\": %s\n", fileName, strerror(error)); exit(1); } // get stat to check the type of the file struct stat st; error = entry.GetStat(&st); if (error != B_OK) { fprintf(stderr, "Error: Failed to stat \"%s\": %s\n", fileName, strerror(error)); exit(1); } bool noPartition = false; int64 partitionOffset = 0; fs_info info; // needs to be here (we use the device name later) if (S_ISDIR(st.st_mode)) { #if defined(__BEOS__) || defined(__ANTARES__) // a directory: get the device error = fs_stat_dev(st.st_dev, &info); if (error != B_OK) { fprintf(stderr, "Error: Failed to determine device for " "\"%s\": %s\n", fileName, strerror(error)); exit(1); } fileName = info.device_name; #else (void)info; fprintf(stderr, "Error: Specifying directories not supported " "on this platform!\n"); exit(1); #endif } else if (S_ISREG(st.st_mode)) { // a regular file: fine noPartition = true; } else if (S_ISCHR(st.st_mode)) { // character special: a device or partition under BeOS // or under FreeBSD #if !(defined(__BEOS__) || defined(__ANTARES__)) && !defined(ANTARES_HOST_PLATFORM_FREEBSD) fprintf(stderr, "Error: Character special devices not " "supported on this platform.\n"); exit(1); #endif #ifdef ANTARES_HOST_PLATFORM_FREEBSD // chop off the trailing number int fileNameLen = strlen(fileName); int baseNameLen = -1; for (int k = fileNameLen - 1; k >= 0; k--) { if (!isdigit(fileName[k])) { baseNameLen = k + 1; break; } } // Remove de 's' from 'ad2s2' slice device (partition for DOS // users) to get 'ad2' base device baseNameLen--; if (baseNameLen < 0) { // only digits? fprintf(stderr, "Error: Failed to get base device name.\n"); exit(1); } if (baseNameLen < fileNameLen) { // get base device name and partition index char baseDeviceName[B_PATH_NAME_LENGTH]; int partitionIndex = atoi(fileName + baseNameLen + 1); // Don't forget the 's' of slice :) memcpy(baseDeviceName, fileName, baseNameLen); baseDeviceName[baseNameLen] = '\0'; // open base device int baseFD = open(baseDeviceName, O_RDONLY); if (baseFD < 0) { fprintf(stderr, "Error: Failed to open \"%s\": %s\n", baseDeviceName, strerror(errno)); exit(1); } // get device size int64 deviceSize; if (ioctl(baseFD, DIOCGMEDIASIZE, &deviceSize) == -1) { fprintf(stderr, "Error: Failed to get device geometry " "for \"%s\": %s\n", baseDeviceName, strerror(errno)); exit(1); } // parse the partition map // TODO: block size! PartitionMapParser parser(baseFD, 0, deviceSize, 512); PartitionMap map; error = parser.Parse(NULL, &map); if (error != B_OK) { fprintf(stderr, "Error: Parsing partition table on " "device \"%s\" failed: %s\n", baseDeviceName, strerror(error)); exit(1); } close(baseFD); // check the partition we are supposed to write at Partition *partition = map.PartitionAt(partitionIndex - 1); if (!partition || partition->IsEmpty()) { fprintf(stderr, "Error: Invalid partition index %d.\n", partitionIndex); dump_partition_map(map); exit(1); } if (partition->IsExtended()) { fprintf(stderr, "Error: Partition %d is an extended " "partition.\n", partitionIndex); dump_partition_map(map); exit(1); } partitionOffset = partition->Offset(); } else { // The given device is the base device. We'll write at // offset 0. } #endif // ANTARES_HOST_PLATFORM_FREEBSD } else if (S_ISBLK(st.st_mode)) { // block device: a device or partition under Linux or Darwin #ifdef ANTARES_HOST_PLATFORM_LINUX // chop off the trailing number int fileNameLen = strlen(fileName); int baseNameLen = -1; for (int k = fileNameLen - 1; k >= 0; k--) { if (!isdigit(fileName[k])) { baseNameLen = k + 1; break; } } if (baseNameLen < 0) { // only digits? fprintf(stderr, "Error: Failed to get base device name.\n"); exit(1); } if (baseNameLen < fileNameLen) { // get base device name and partition index char baseDeviceName[B_PATH_NAME_LENGTH]; int partitionIndex = atoi(fileName + baseNameLen); memcpy(baseDeviceName, fileName, baseNameLen); baseDeviceName[baseNameLen] = '\0'; // open base device int baseFD = open(baseDeviceName, O_RDONLY); if (baseFD < 0) { fprintf(stderr, "Error: Failed to open \"%s\": %s\n", baseDeviceName, strerror(errno)); exit(1); } // get device size -- try BLKGETSIZE64, but, if it doesn't // work, fall back to the obsolete HDIO_GETGEO int64 deviceSize; hd_geometry geometry; if (ioctl(baseFD, BLKGETSIZE64, &deviceSize) == 0 && deviceSize > 0) { // looks good } else if (ioctl(baseFD, HDIO_GETGEO, &geometry) == 0) { deviceSize = (int64)geometry.heads * geometry.sectors * geometry.cylinders * 512; } else { fprintf(stderr, "Error: Failed to get device geometry " "for \"%s\": %s\n", baseDeviceName, strerror(errno)); exit(1); } // parse the partition map // TODO: block size! PartitionMapParser parser(baseFD, 0, deviceSize, 512); PartitionMap map; error = parser.Parse(NULL, &map); if (error != B_OK) { fprintf(stderr, "Error: Parsing partition table on " "device \"%s\" failed: %s\n", baseDeviceName, strerror(error)); exit(1); } close(baseFD); // check the partition we are supposed to write at Partition *partition = map.PartitionAt(partitionIndex - 1); if (!partition || partition->IsEmpty()) { fprintf(stderr, "Error: Invalid partition index %d.\n", partitionIndex); dump_partition_map(map); exit(1); } if (partition->IsExtended()) { fprintf(stderr, "Error: Partition %d is an extended " "partition.\n", partitionIndex); dump_partition_map(map); exit(1); } partitionOffset = partition->Offset(); } else { // The given device is the base device. We'll write at // offset 0. } #elif defined(ANTARES_HOST_PLATFORM_DARWIN) // chop off the trailing number int fileNameLen = strlen(fileName); int baseNameLen = fileNameLen - 2; // get base device name and partition index char baseDeviceName[B_PATH_NAME_LENGTH]; int partitionIndex = atoi(fileName + baseNameLen + 1); memcpy(baseDeviceName, fileName, baseNameLen); baseDeviceName[baseNameLen] = '\0'; // open base device int baseFD = open(baseDeviceName, O_RDONLY); if (baseFD < 0) { fprintf(stderr, "Error: Failed to open \"%s\": %s\n", baseDeviceName, strerror(errno)); exit(1); } // get device size int64 blockSize; int64 blockCount; int64 deviceSize; if (ioctl(baseFD, DKIOCGETBLOCKSIZE, &blockSize) == -1) { fprintf(stderr, "Error: Failed to get block size " "for \"%s\": %s\n", baseDeviceName, strerror(errno)); exit(1); } if (ioctl(baseFD, DKIOCGETBLOCKCOUNT, &blockCount) == -1) { fprintf(stderr, "Error: Failed to get block count " "for \"%s\": %s\n", baseDeviceName, strerror(errno)); exit(1); } deviceSize = blockSize * blockCount; // parse the partition map PartitionMapParser parser(baseFD, 0, deviceSize, blockSize); PartitionMap map; error = parser.Parse(NULL, &map); if (error != B_OK) { fprintf(stderr, "Error: Parsing partition table on " "device \"%s\" failed: %s\n", baseDeviceName, strerror(error)); exit(1); } close(baseFD); // check the partition we are supposed to write at Partition *partition = map.PartitionAt(partitionIndex - 1); if (!partition || partition->IsEmpty()) { fprintf(stderr, "Error: Invalid partition index %d.\n", partitionIndex); dump_partition_map(map); exit(1); } if (partition->IsExtended()) { fprintf(stderr, "Error: Partition %d is an extended " "partition.\n", partitionIndex); dump_partition_map(map); exit(1); } partitionOffset = partition->Offset(); #else // partitions are block devices under Antares, but not under BeOS #ifndef __ANTARES__ fprintf(stderr, "Error: Block devices not supported on this " "platform!\n"); exit(1); #endif // __ANTARES__ #endif } else { fprintf(stderr, "Error: File type of \"%s\" is not supported.\n", fileName); exit(1); } // open the file int fd = open(fileName, O_RDWR); if (fd < 0) { fprintf(stderr, "Error: Failed to open \"%s\": %s\n", fileName, strerror(errno)); exit(1); } #if (defined(__BEOS__) || defined(__ANTARES__)) // get a partition info if (!noPartition && strlen(fileName) >= 3 && strncmp("raw", fileName + strlen(fileName) - 3, 3)) { partition_info partitionInfo; if (ioctl(fd, B_GET_PARTITION_INFO, &partitionInfo, sizeof(partitionInfo)) == 0) { partitionOffset = partitionInfo.offset; } else { fprintf(stderr, "Error: Failed to get partition info: %s\n", strerror(errno)); exit(1); } } #endif // __BEOS__ // adjust the partition offset in the boot code data // hard coded sector size: 512 bytes *(uint32*)(bootCodeData + kPartitionOffsetOffset) = B_HOST_TO_LENDIAN_INT32((uint32)(partitionOffset / 512)); // write the boot code printf("Writing boot code to \"%s\" (partition offset: %" B_PRId64 " bytes, start offset = %" B_PRIdOFF ") " "...\n", fileName, partitionOffset, startOffset); write_boot_code_part(fileName, fd, startOffset, bootCodeData, 0, kFirstBootCodePartSize, dryRun); write_boot_code_part(fileName, fd, startOffset, bootCodeData, kSecondBootCodePartOffset, kSecondBootCodePartSize, dryRun); #ifdef __ANTARES__ // check if this partition is mounted BDiskDeviceRoster roster; BPartition* partition; BDiskDevice device; status_t status = roster.GetPartitionForPath(fileName, &device, &partition); if (status != B_OK) { status = roster.GetFileDeviceForPath(fileName, &device); if (status == B_OK) partition = &device; } if (status == B_OK && partition->IsMounted() && !dryRun) { // This partition is mounted, we need to tell BFS to update its // boot block (we are using part of the same logical block). BPath path; status = partition->GetMountPoint(&path); if (status == B_OK) { update_boot_block update; update.offset = kSecondBootCodePartOffset - 512; update.data = bootCodeData + kSecondBootCodePartOffset; update.length = kSecondBootCodePartSize; int mountFD = open(path.Path(), O_RDONLY); if (ioctl(mountFD, BFS_IOCTL_UPDATE_BOOT_BLOCK, &update, sizeof(update_boot_block)) != 0) { fprintf(stderr, "Could not update BFS boot block: %s\n", strerror(errno)); } close(mountFD); } else { fprintf(stderr, "Could not update BFS boot code while the " "partition is mounted!\n"); } } #endif // __ANTARES__ close(fd); } return 0; }