1 /* 2 * Copyright 2002-2005, Axel Dörfler, axeld@pinc-software.de. 3 * Distributed under the terms of the MIT License. 4 * 5 * Copyright 2001-2002, Travis Geiselbrecht. All rights reserved. 6 * Distributed under the terms of the NewOS License. 7 */ 8 9 10 #include <OS.h> 11 #include <fs_info.h> 12 13 #include <disk_device_manager/KDiskDevice.h> 14 #include <disk_device_manager/KDiskDeviceManager.h> 15 #include <disk_device_manager/KPartitionVisitor.h> 16 #include <DiskDeviceTypes.h> 17 18 #include <vfs.h> 19 #include <file_cache.h> 20 #include <KPath.h> 21 #include <syscalls.h> 22 #include <boot/kernel_args.h> 23 #include <util/Stack.h> 24 25 #include <stdio.h> 26 27 28 //#define TRACE_VFS 29 #ifdef TRACE_VFS 30 # define PRINT(x) dprintf x 31 # define FUNCTION(x) dprintf x 32 #else 33 # define PRINT(x) ; 34 # define FUNCTION(x) ; 35 #endif 36 37 38 typedef Stack<KPartition *> PartitionStack; 39 40 static struct { 41 const char *path; 42 const char *target; 43 } sPredefinedLinks[] = { 44 {"/system", "/boot/beos/system"}, 45 {"/bin", "/boot/beos/bin"}, 46 {"/etc", "/boot/beos/etc"}, 47 {"/var", "/boot/var"}, 48 {"/tmp", "/boot/var/tmp"}, 49 {NULL} 50 }; 51 52 // This can be used by other code to see if there is a boot file system already 53 dev_t gBootDevice = -1; 54 55 56 /** No image was chosen - prefer disks with names like "Haiku", or "System" 57 */ 58 59 static int 60 compare_image_boot(const void *_a, const void *_b) 61 { 62 KPartition *a = *(KPartition **)_a; 63 KPartition *b = *(KPartition **)_b; 64 65 if (a->ContentName() != NULL) { 66 if (b->ContentName() == NULL) 67 return 1; 68 } else if (b->ContentName() != NULL) { 69 return -1; 70 } else 71 return 0; 72 73 int compare = strcmp(a->ContentName(), b->ContentName()); 74 if (!compare) 75 return 0; 76 77 if (!strcasecmp(a->ContentName(), "Haiku")) 78 return 1; 79 if (!strcasecmp(b->ContentName(), "Haiku")) 80 return -1; 81 if (!strncmp(a->ContentName(), "System", 6)) 82 return 1; 83 if (!strncmp(b->ContentName(), "System", 6)) 84 return -1; 85 86 return compare; 87 } 88 89 90 /** The system was booted from CD - prefer CDs over other entries. If there 91 * is no CD, fall back to the standard mechanism (as implemented by 92 * compare_image_boot(). 93 */ 94 95 static int 96 compare_cd_boot(const void *_a, const void *_b) 97 { 98 KPartition *a = *(KPartition **)_a; 99 KPartition *b = *(KPartition **)_b; 100 101 bool aIsCD = a->Type() != NULL && !strcmp(a->Type(), kPartitionTypeDataSession); 102 bool bIsCD = b->Type() != NULL && !strcmp(b->Type(), kPartitionTypeDataSession); 103 104 int compare = (int)aIsCD - (int)bIsCD; 105 if (compare != 0) 106 return compare; 107 108 return compare_image_boot(_a, _b); 109 } 110 111 112 static status_t 113 get_boot_partitions(kernel_args *args, PartitionStack &partitions) 114 { 115 // make the boot partition (and probably others) available 116 KDiskDeviceManager::CreateDefault(); 117 KDiskDeviceManager *manager = KDiskDeviceManager::Default(); 118 119 status_t status = manager->InitialDeviceScan(); 120 if (status == B_OK) { 121 // ToDo: do this for real... (no hacks allowed :)) 122 for (;;) { 123 snooze(500000); 124 if (manager->CountJobs() == 0) 125 break; 126 } 127 } else { 128 dprintf("KDiskDeviceManager::InitialDeviceScan() failed: %s\n", strerror(status)); 129 return status; 130 } 131 132 // ToDo: do this for real! It will currently only use the partition offset; 133 // it does not yet use the disk_identifier information. 134 135 struct BootPartitionVisitor : KPartitionVisitor { 136 BootPartitionVisitor(kernel_args &args, PartitionStack &stack) 137 : fArgs(args), fPartitions(stack) {} 138 139 virtual bool VisitPre(KPartition *partition) 140 { 141 if (!partition->ContainsFileSystem()) 142 return false; 143 144 if (!fArgs.boot_disk.booted_from_image) { 145 // the simple case: we can just boot from the selected boot device 146 if (partition->Offset() == fArgs.boot_disk.partition_offset) { 147 fPartitions.Push(partition); 148 return true; 149 } 150 } else { 151 // for now, we will just collect all BFS volumes 152 if (fArgs.boot_disk.cd && fArgs.boot_disk.user_selected 153 && partition->Type() != NULL 154 && strcmp(partition->Type(), kPartitionTypeDataSession)) 155 return false; 156 157 if (partition->ContentType() != NULL 158 && !strcmp(partition->ContentType(), "Be File System")) 159 fPartitions.Push(partition); 160 } 161 return false; 162 } 163 private: 164 kernel_args &fArgs; 165 PartitionStack &fPartitions; 166 } visitor(*args, partitions); 167 168 KDiskDevice *device; 169 int32 cookie = 0; 170 while ((device = manager->NextDevice(&cookie)) != NULL) { 171 if (device->VisitEachDescendant(&visitor) != NULL) 172 break; 173 } 174 175 if (!args->boot_disk.user_selected) { 176 // sort partition list (ie. when booting from CD, CDs should come first in the list) 177 qsort(partitions.Array(), partitions.CountItems(), sizeof(KPartition *), 178 args->boot_disk.cd ? compare_cd_boot : compare_image_boot); 179 } 180 181 return B_OK; 182 } 183 184 185 // #pragma mark - 186 187 188 status_t 189 vfs_bootstrap_file_systems(void) 190 { 191 status_t status; 192 193 // bootstrap the root filesystem 194 status = _kern_mount("/", NULL, "rootfs", 0, NULL); 195 if (status < B_OK) 196 panic("error mounting rootfs!\n"); 197 198 _kern_setcwd(-1, "/"); 199 200 // bootstrap the devfs 201 _kern_create_dir(-1, "/dev", 0755); 202 status = _kern_mount("/dev", NULL, "devfs", 0, NULL); 203 if (status < B_OK) 204 panic("error mounting devfs\n"); 205 206 // bootstrap the pipefs 207 _kern_create_dir(-1, "/pipe", 0755); 208 status = _kern_mount("/pipe", NULL, "pipefs", 0, NULL); 209 if (status < B_OK) 210 panic("error mounting pipefs\n"); 211 212 // create directory for the boot volume 213 _kern_create_dir(-1, "/boot", 0755); 214 215 // create some standard links on the rootfs 216 217 for (int32 i = 0; sPredefinedLinks[i].path != NULL; i++) { 218 _kern_create_symlink(-1, sPredefinedLinks[i].path, 219 sPredefinedLinks[i].target, 0); 220 // we don't care if it will succeed or not 221 } 222 223 return B_OK; 224 } 225 226 227 status_t 228 vfs_mount_boot_file_system(kernel_args *args) 229 { 230 PartitionStack partitions; 231 status_t status = get_boot_partitions(args, partitions); 232 if (status < B_OK) { 233 panic("Did not get any boot partitions!"); 234 return status; 235 } 236 237 KPartition *bootPartition; 238 while (partitions.Pop(&bootPartition)) { 239 KPath path; 240 if (bootPartition->GetPath(&path) != B_OK) 241 panic("could not get boot device!\n"); 242 243 gBootDevice = _kern_mount("/boot", path.Path(), NULL, 0, NULL); 244 if (gBootDevice >= B_OK) 245 break; 246 } 247 248 if (gBootDevice < B_OK) 249 panic("could not mount boot device!\n"); 250 251 // create link for the name of the boot device 252 253 fs_info info; 254 if (_kern_read_fs_info(gBootDevice, &info) == B_OK) { 255 char path[B_FILE_NAME_LENGTH + 1]; 256 snprintf(path, sizeof(path), "/%s", info.volume_name); 257 258 _kern_create_symlink(-1, path, "/boot", 0); 259 } 260 261 file_cache_init_post_boot_device(); 262 return B_OK; 263 } 264 265