xref: /haiku/src/bin/mountvolume.cpp (revision fef6144999c2fa611f59ee6ffe6dd7999501385c)
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