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\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
36int
37main(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