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