xref: /haiku/src/bin/mountvolume.cpp (revision 24159a0c7d6d6dcba9f2a0c1a7c08d2c8167f21b)
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 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 = !partition->IsMounted();
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 		// check whether to unmount
134 		bool unmount = false;
135 		if (name && toUnmount.find(name) != toUnmount.end()) {
136 			toUnmount.erase(name);
137 			if (!partition->IsMounted()) {
138 				unmount = true;
139 				mount = false;
140 			} else if (!silent)
141 				fprintf(stderr, "Volume `%s' not mounted.\n", name);
142 		}
143 
144 		// mount/unmount
145 		if (mount) {
146 			status_t error = partition->Mount(NULL,
147 				(readOnly ? B_MOUNT_READ_ONLY : 0));
148 			if (!silent) {
149 				if (error >= B_OK) {
150 					BPath mountPoint;
151 					partition->GetMountPoint(&mountPoint);
152 					printf("Volume `%s' mounted successfully at '%s'.\n", name, mountPoint.Path());
153 				} else {
154 					fprintf(stderr, "Failed to mount volume `%s': %s\n",
155 						name, strerror(error));
156 				}
157 			}
158 		} else if (unmount) {
159 			status_t error = partition->Unmount();
160 			if (!silent) {
161 				if (error == B_OK) {
162 					printf("Volume `%s' unmounted successfully.\n", name);
163 				} else {
164 					fprintf(stderr, "Failed to unmount volume `%s': %s\n",
165 						name, strerror(error));
166 				}
167 			}
168 		}
169 
170 		return false;
171 	}
172 
173 	bool		silent;
174 	StringSet	toMount;
175 	StringSet	toUnmount;
176 	bool		mountAll;
177 	bool		mountBFS;
178 	bool		mountHFS;
179 	bool		mountDOS;
180 	bool		readOnly;
181 };
182 
183 // PrintPartitionsVisitor
184 struct PrintPartitionsVisitor : public BDiskDeviceVisitor {
185 	PrintPartitionsVisitor()
186 		: listMountablePartitions(false),
187 		  listAllPartitions(false)
188 	{
189 	}
190 
191 	bool IsUsed()
192 	{
193 		return listMountablePartitions || listAllPartitions;
194 	}
195 
196 	virtual bool Visit(BDiskDevice *device)
197 	{
198 		return Visit(device, 0);
199 	}
200 
201 	virtual bool Visit(BPartition *partition, int32 level)
202 	{
203 		// get name and type
204 		const char *name = partition->ContentName();
205 		if (name == NULL || name[0] == '\0') {
206 			name = partition->Name();
207 			if (name == NULL || name[0] == '\0') {
208 				if (partition->ContainsFileSystem())
209 					name = "<unnamed>";
210 				else
211 					name = "";
212 			}
213 		}
214 		const char *type = partition->ContentType();
215 		if (type == NULL)
216 			type = "<unknown>";
217 
218 		BPath path;
219 		if (partition->IsMounted())
220 			partition->GetMountPoint(&path);
221 
222 		printf("%-16s %-20s %s\n",
223 			name, type, partition->IsMounted() ? path.Path() : "");
224 		return false;
225 	}
226 
227 	bool listMountablePartitions;
228 	bool listAllPartitions;
229 };
230 
231 
232 // main
233 int
234 main(int argc, char **argv)
235 {
236 	if (argc < 2)
237 		print_usage_and_exit(true);
238 
239 	MountVisitor mountVisitor;
240 	PrintPartitionsVisitor printPartitionsVisitor;
241 	bool listAllDevices = false;
242 
243 	// parse arguments
244 
245 	for (int argi = 1; argi < argc; argi++) {
246 		const char *arg = argv[argi];
247 
248 		if (arg[0] != '\0' && arg[0] != '-') {
249 			mountVisitor.toMount.insert(arg);
250 		} else if (strcmp(arg, "-s") == 0) {
251 			mountVisitor.silent = true;
252 		} else if (strcmp(arg, "-h") == 0 || strcmp(arg, "--help") == 0) {
253 			print_usage_and_exit(false);
254 		} else if (strcmp(arg, "-all") == 0) {
255 			mountVisitor.mountAll = true;
256 		} else if (strcmp(arg, "-allbfs") == 0) {
257 			mountVisitor.mountBFS = true;
258 		} else if (strcmp(arg, "-allhfs") == 0) {
259 			mountVisitor.mountHFS = true;
260 		} else if (strcmp(arg, "-alldos") == 0) {
261 			mountVisitor.mountDOS = true;
262 		} else if (strcmp(arg, "-ro") == 0) {
263 			mountVisitor.readOnly = true;
264 		} else if (strcmp(arg, "-unmount") == 0) {
265 			argi++;
266 			if (argi >= argc)
267 				print_usage_and_exit(true);
268 			mountVisitor.toUnmount.insert(argv[argi]);
269 		} else if (strcmp(arg, "-p") == 0 || strcmp(arg, "-l") == 0) {
270 			printPartitionsVisitor.listMountablePartitions = true;
271 		} else if (strcmp(arg, "-lh") == 0) {
272 			printPartitionsVisitor.listAllPartitions = true;
273 		} else if (strcmp(arg, "-dd") == 0) {
274 			listAllDevices = true;
275 		} else if (strcmp(arg, "-r") == 0 || strcmp(arg, "-publishall") == 0
276 			|| strcmp(arg, "-publishbfs") == 0
277 			|| strcmp(arg, "-publishhfs") == 0
278 			|| strcmp(arg, "-publishdos") == 0) {
279 			// obsolete: ignore
280 		} else
281 			print_usage_and_exit(true);
282 	}
283 
284 	// get a disk device list
285 	BDiskDeviceList deviceList;
286 	status_t error = deviceList.Fetch();
287 	if (error != B_OK) {
288 		fprintf(stderr, "Failed to get the list of disk devices: %s",
289 			strerror(error));
290 		exit(1);
291 	}
292 
293 	// mount/unmount volumes
294 	deviceList.VisitEachMountablePartition(&mountVisitor);
295 
296 	// print errors for the volumes to mount/unmount, that weren't found
297 	if (!mountVisitor.silent) {
298 		for (StringSet::iterator it = mountVisitor.toMount.begin();
299 			 it != mountVisitor.toMount.end();
300 			 it++) {
301 			fprintf(stderr, "Failed to mount volume `%s': Volume not found.\n",
302 				(*it).c_str());
303 		}
304 		for (StringSet::iterator it = mountVisitor.toUnmount.begin();
305 			 it != mountVisitor.toUnmount.end();
306 			 it++) {
307 			fprintf(stderr, "Failed to unmount volume `%s': Volume not found.\n",
308 				(*it).c_str());
309 		}
310 	}
311 
312 	// update the disk device list
313 	error = deviceList.Fetch();
314 	if (error != B_OK) {
315 		fprintf(stderr, "Failed to update the list of disk devices: %s",
316 			strerror(error));
317 		exit(1);
318 	}
319 
320 	// print information
321 
322 	if (listAllDevices) {
323 		// TODO
324 	}
325 
326 	if (printPartitionsVisitor.IsUsed()) {
327 		puts("Volume           File System          Mounted At");
328 		puts("----------------------------------------------------------");
329 
330 		if (printPartitionsVisitor.listAllPartitions)
331 			deviceList.VisitEachPartition(&printPartitionsVisitor);
332 		else
333 			deviceList.VisitEachMountablePartition(&printPartitionsVisitor);
334 	}
335 
336 	return 0;
337 }
338