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