1 /* 2 * Copyright 2005, Ingo Weinhold, bonefish@users.sf.net. All rights reserved. 3 * Distributed under the terms of the MIT License. 4 */ 5 6 7 #include <stdio.h> 8 #include <string.h> 9 10 #include <set> 11 #include <string> 12 13 #include <DiskDevice.h> 14 #include <DiskDevicePrivate.h> 15 #include <DiskDeviceRoster.h> 16 #include <DiskDeviceTypes.h> 17 #include <DiskDeviceList.h> 18 #include <Partition.h> 19 20 #include <Path.h> 21 #include <fs_volume.h> 22 23 extern const char *__progname; 24 25 26 typedef set<string> StringSet; 27 28 // usage 29 static const char *kUsage = 30 "%s <options> [ <volume name> ... ]\n" 31 "Mounts the volume with name <volume name>, if given. Lists info about\n" 32 "mounted and mountable volumes and mounts/unmounts volumes.\n" 33 "\n" 34 "The terminology is actually not quite correct: By volumes only partitions\n" 35 "living on disk devices are meant.\n" 36 "\n" 37 "Options:\n" 38 "[general]\n" 39 " -s - silent; don't print info about (un)mounting\n" 40 " -h, --help - print this info text\n" 41 "\n" 42 "[mounting]\n" 43 " -all - mount all mountable volumes\n" 44 " -allbfs - mount all mountable BFS volumes\n" 45 " -allhfs - mount all mountable HFS volumes\n" 46 " -alldos - mount all mountable DOS volumes\n" 47 " -ro - mount volumes read-only\n" 48 " -unmount <volume> - unmount the volume with the name <volume>\n" 49 "\n" 50 "[info]\n" 51 " -p, -l - list all mounted and mountable volumes\n" 52 " -lh - list all existing volumes (incl. not-mountable ones)\n" 53 " -dd - list all disk existing devices\n" 54 "\n" 55 "[obsolete]\n" 56 " -r - ignored\n" 57 " -publishall - ignored\n" 58 " -publishbfs - ignored\n" 59 " -publishhfs - ignored\n" 60 " -publishdos - ignored\n"; 61 62 // application name 63 const char *kAppName = __progname; 64 65 66 // print_usage 67 static 68 void 69 print_usage(bool error) 70 { 71 fprintf(error ? stderr : stdout, kUsage, kAppName); 72 } 73 74 // print_usage_and_exit 75 static 76 void 77 print_usage_and_exit(bool error) 78 { 79 print_usage(error); 80 exit(error ? 0 : 1); 81 } 82 83 // MountVisitor 84 struct MountVisitor : public BDiskDeviceVisitor { 85 MountVisitor() 86 : silent(false), 87 mountAll(false), 88 mountBFS(false), 89 mountHFS(false), 90 mountDOS(false), 91 readOnly(false) 92 { 93 } 94 95 virtual bool Visit(BDiskDevice *device) 96 { 97 return Visit(device, 0); 98 } 99 100 virtual bool Visit(BPartition *partition, int32 level) 101 { 102 // get name and type 103 const char *name = partition->ContentName(); 104 if (!name) 105 name = partition->Name(); 106 const char *type = partition->ContentType(); 107 108 // check whether to mount 109 bool mount = false; 110 if (name && toMount.find(name) != toMount.end()) { 111 toMount.erase(name); 112 if (!partition->IsMounted()) 113 mount = true; 114 else if (!silent) 115 fprintf(stderr, "Volume `%s' already mounted.\n", name); 116 } else if (mountAll) { 117 mount = true; 118 } else if (mountBFS && type != NULL 119 && strcmp(type, kPartitionTypeBFS) == 0) { 120 mount = true; 121 } else if (mountHFS && type != NULL 122 && strcmp(type, kPartitionTypeHFS) == 0) { 123 mount = true; 124 } else if (mountDOS && type != NULL 125 && (strcmp(type, kPartitionTypeFAT12) == 0 126 || strcmp(type, kPartitionTypeFAT32) == 0)) { 127 mount = true; 128 } 129 130 // check whether to unmount 131 bool unmount = false; 132 if (name && toUnmount.find(name) != toUnmount.end()) { 133 toUnmount.erase(name); 134 if (!partition->IsMounted()) { 135 unmount = true; 136 mount = false; 137 } else if (!silent) 138 fprintf(stderr, "Volume `%s' not mounted.\n", name); 139 } 140 141 // mount/unmount 142 if (mount) { 143 status_t error = partition->Mount(NULL, 144 (readOnly ? B_MOUNT_READ_ONLY : 0)); 145 if (!silent) { 146 if (error == B_OK) { 147 printf("Volume `%s' mounted successfully.\n", name); 148 } else { 149 fprintf(stderr, "Failed to mount volume `%s': %s\n", 150 name, strerror(error)); 151 } 152 } 153 } else if (unmount) { 154 status_t error = partition->Unmount(); 155 if (!silent) { 156 if (error == B_OK) { 157 printf("Volume `%s' unmounted successfully.\n", name); 158 } else { 159 fprintf(stderr, "Failed to unmount volume `%s': %s\n", 160 name, strerror(error)); 161 } 162 } 163 } 164 165 return false; 166 } 167 168 bool silent; 169 StringSet toMount; 170 StringSet toUnmount; 171 bool mountAll; 172 bool mountBFS; 173 bool mountHFS; 174 bool mountDOS; 175 bool readOnly; 176 }; 177 178 // PrintPartitionsVisitor 179 struct PrintPartitionsVisitor : public BDiskDeviceVisitor { 180 PrintPartitionsVisitor() 181 : listMountablePartitions(false), 182 listAllPartitions(false) 183 { 184 } 185 186 bool IsUsed() 187 { 188 return listMountablePartitions || listAllPartitions; 189 } 190 191 virtual bool Visit(BDiskDevice *device) 192 { 193 return Visit(device, 0); 194 } 195 196 virtual bool Visit(BPartition *partition, int32 level) 197 { 198 // get name and type 199 const char *name = partition->ContentName(); 200 if (name == NULL || name[0] == '\0') { 201 name = partition->Name(); 202 if (name == NULL || name[0] == '\0') { 203 if (partition->ContainsFileSystem()) 204 name = "<unnamed>"; 205 else 206 name = ""; 207 } 208 } 209 const char *type = partition->ContentType(); 210 if (type == NULL) 211 type = "<unknown>"; 212 213 BPath path; 214 if (partition->IsMounted()) 215 partition->GetMountPoint(&path); 216 217 printf("%-16s %-20s %s\n", 218 name, type, partition->IsMounted() ? path.Path() : ""); 219 return false; 220 } 221 222 bool listMountablePartitions; 223 bool listAllPartitions; 224 }; 225 226 227 // main 228 int 229 main(int argc, char **argv) 230 { 231 if (argc < 2) 232 print_usage_and_exit(true); 233 234 MountVisitor mountVisitor; 235 PrintPartitionsVisitor printPartitionsVisitor; 236 bool listAllDevices = false; 237 238 // parse arguments 239 240 for (int argi = 1; argi < argc; argi++) { 241 const char *arg = argv[argi]; 242 243 if (arg[0] != '\0' && arg[0] != '-') { 244 mountVisitor.toMount.insert(arg); 245 } else if (strcmp(arg, "-s") == 0) { 246 mountVisitor.silent = true; 247 } else if (strcmp(arg, "-h") == 0 || strcmp(arg, "--help") == 0) { 248 print_usage_and_exit(false); 249 } else if (strcmp(arg, "-all") == 0) { 250 mountVisitor.mountAll = true; 251 } else if (strcmp(arg, "-allbfs") == 0) { 252 mountVisitor.mountBFS = true; 253 } else if (strcmp(arg, "-allhfs") == 0) { 254 mountVisitor.mountHFS = true; 255 } else if (strcmp(arg, "-alldos") == 0) { 256 mountVisitor.mountDOS = true; 257 } else if (strcmp(arg, "-ro") == 0) { 258 mountVisitor.readOnly = true; 259 } else if (strcmp(arg, "-unmount") == 0) { 260 argi++; 261 if (argi >= argc) 262 print_usage_and_exit(true); 263 mountVisitor.toUnmount.insert(argv[argi]); 264 } else if (strcmp(arg, "-p") == 0 || strcmp(arg, "-l") == 0) { 265 printPartitionsVisitor.listMountablePartitions = true; 266 } else if (strcmp(arg, "-lh") == 0) { 267 printPartitionsVisitor.listAllPartitions = true; 268 } else if (strcmp(arg, "-dd") == 0) { 269 listAllDevices = true; 270 } else if (strcmp(arg, "-r") == 0 || strcmp(arg, "-publishall") == 0 271 || strcmp(arg, "-publishbfs") == 0 272 || strcmp(arg, "-publishhfs") == 0 273 || strcmp(arg, "-publishdos") == 0) { 274 // obsolete: ignore 275 } else 276 print_usage_and_exit(true); 277 } 278 279 // get a disk device list 280 BDiskDeviceList deviceList; 281 status_t error = deviceList.Fetch(); 282 if (error != B_OK) { 283 fprintf(stderr, "Failed to get the list of disk devices: %s", 284 strerror(error)); 285 exit(1); 286 } 287 288 // mount/unmount volumes 289 deviceList.VisitEachMountablePartition(&mountVisitor); 290 291 // print errors for the volumes to mount/unmount, that weren't found 292 if (!mountVisitor.silent) { 293 for (StringSet::iterator it = mountVisitor.toMount.begin(); 294 it != mountVisitor.toMount.end(); 295 it++) { 296 fprintf(stderr, "Failed to mount volume `%s': Volume not found.\n", 297 (*it).c_str()); 298 } 299 for (StringSet::iterator it = mountVisitor.toUnmount.begin(); 300 it != mountVisitor.toUnmount.end(); 301 it++) { 302 fprintf(stderr, "Failed to unmount volume `%s': Volume not found.\n", 303 (*it).c_str()); 304 } 305 } 306 307 // update the disk device list 308 error = deviceList.Fetch(); 309 if (error != B_OK) { 310 fprintf(stderr, "Failed to update the list of disk devices: %s", 311 strerror(error)); 312 exit(1); 313 } 314 315 // print information 316 317 if (listAllDevices) { 318 // TODO 319 } 320 321 if (printPartitionsVisitor.IsUsed()) { 322 puts("Volume File System Mounted At"); 323 puts("----------------------------------------------------------"); 324 325 if (printPartitionsVisitor.listAllPartitions) 326 deviceList.VisitEachPartition(&printPartitionsVisitor); 327 else 328 deviceList.VisitEachMountablePartition(&printPartitionsVisitor); 329 } 330 331 return 0; 332 } 333