xref: /haiku/src/bin/checkfs.cpp (revision 17889a8c70dbb3d59c1412f6431968753c767bab)
1 /*
2  * Copyright 2008, Axel Dörfler, axeld@pinc-software.de.
3  * Distributed under the terms of the MIT License.
4  */
5 
6 
7 #include <getopt.h>
8 #include <stdio.h>
9 
10 #include <DiskDevice.h>
11 #include <DiskDeviceRoster.h>
12 #include <DiskSystem.h>
13 
14 
15 extern "C" const char* __progname;
16 static const char* kProgramName = __progname;
17 
18 
19 void
20 usage(FILE* output)
21 {
22 	fprintf(output,
23 		"Usage: %s <options> <device|volume name>\n"
24 		"\n"
25 		"Options:\n"
26 		"  -h, --help\t\t- print this help text\n"
27 		"  -c, --check-only\t- do not make any changes to the file system\n"
28 		"\n"
29 		"Examples:\n"
30 		"  %s -c /Haiku\n"
31 		"  %s /dev/disk/ata/0/master/raw\n",
32 		kProgramName, kProgramName, kProgramName);
33 }
34 
35 
36 int
37 main(int argc, char** argv)
38 {
39 	const struct option kLongOptions[] = {
40 		{ "help", 0, NULL, 'h' },
41 		{ "check-only", 0, NULL, 'c' },
42 		{ NULL, 0, NULL, 0 }
43 	};
44 	const char* kShortOptions = "hc";
45 
46 	// parse argument list
47 	bool checkOnly = false;
48 
49 	while (true) {
50 		int nextOption = getopt_long(argc, argv, kShortOptions, kLongOptions,
51 			NULL);
52 		if (nextOption == -1)
53 			break;
54 
55 		switch (nextOption) {
56 			case 'h':	// --help
57 				usage(stdout);
58 				return 0;
59 			case 'c':	// --check-only
60 				checkOnly = true;
61 				break;
62 			default:	// everything else
63 				usage(stderr);
64 				return 1;
65 		}
66 	}
67 
68 	// the device name should be the only non-option element
69 	if (optind != argc - 1) {
70 		usage(stderr);
71 		return 1;
72 	}
73 
74 	const char* path = argv[optind];
75 	//UnregisterFileDevice unregisterFileDevice;
76 
77 	BDiskDeviceRoster roster;
78 	BPartition* partition;
79 	BDiskDevice device;
80 
81 	status_t status = roster.GetPartitionForPath(path, &device,
82 		&partition);
83 	if (status != B_OK) {
84 		if (strncmp(path, "/dev", 4)) {
85 			// try mounted volume
86 			status = roster.FindPartitionByMountPoint(path, &device, &partition)
87 				? B_OK : B_BAD_VALUE;
88 		}
89 
90 		// TODO: try to register file device
91 
92 		if (status != B_OK) {
93 			fprintf(stderr, "%s: Failed to get disk device for path \"%s\": "
94 				"%s\n", kProgramName, path, strerror(status));
95 			return 1;
96 		}
97 	}
98 
99 	// Prepare the device for modifications
100 
101 	status = device.PrepareModifications();
102 	if (status != B_OK) {
103 		fprintf(stderr, "%s: Could not prepare the device for modifications: "
104 			"%s\n", kProgramName, strerror(status));
105 		return 1;
106 	}
107 
108 	// Check if the partition supports repairing
109 
110 	bool canRepairWhileMounted;
111 	bool canRepair = partition->CanRepair(checkOnly, &canRepairWhileMounted);
112 	if (!canRepair && !canRepairWhileMounted) {
113 		fprintf(stderr, "%s: The disk system does not support repairing.\n",
114 			kProgramName);
115 		return 1;
116 	}
117 
118 	if (partition->IsMounted() && !canRepairWhileMounted) {
119 		fprintf(stderr, "%s: The disk system does not support repairing a "
120 			"mounted volume.\n", kProgramName);
121 		return 1;
122 	}
123 	if (!partition->IsMounted() && !canRepair) {
124 		fprintf(stderr, "%s: The disk system does not support repairing a "
125 			"volume that is not mounted.\n", kProgramName);
126 		return 1;
127 	}
128 
129 	BDiskSystem diskSystem;
130 	status = partition->GetDiskSystem(&diskSystem);
131 	if (status != B_OK) {
132 		fprintf(stderr, "%s: Failed to get disk system for partition: %s\n",
133 			kProgramName, strerror(status));
134 		return 1;
135 	}
136 
137 	// Repair the volume
138 
139 	status = partition->Repair(checkOnly);
140 	if (status != B_OK) {
141 		fprintf(stderr, "%s: Repairing failed: %s\n", kProgramName,
142 			strerror(status));
143 		return 1;
144 	}
145 
146 	status = device.CommitModifications();
147 
148 	return 0;
149 }
150