1/*
2 * Copyright 2012, Andreas Henriksson, sausageboy@gmail.com.
3 * Copyright 2008, Axel D��rfler, axeld@pinc-software.de.
4 * Distributed under the terms of the MIT License.
5 */
6
7
8#include <stdio.h>
9
10#include <DiskDevice.h>
11#include <DiskDeviceRoster.h>
12#include <DiskSystem.h>
13#include <StringForSize.h>
14
15
16extern "C" const char* __progname;
17static const char* kProgramName = __progname;
18
19
20int
21main(int argc, char** argv)
22{
23	if (argc != 3) {
24		fprintf(stderr, "Usage: %s <device> <size>\n"
25			"Resize volume on <device> to new size <size> (in bytes, suffixes "
26			"'k', 'm', 'g', 't' are interpreted as KiB, Mib, GiB, TiB).\n",
27			kProgramName);
28		return 1;
29	}
30
31	int64 size = parse_size(argv[2]);
32	if (size <= 0) {
33		fprintf(stderr, "%s: The new size \"%s\" is not a number\n",
34			kProgramName, argv[2]);
35		return 1;
36	}
37
38	BDiskDeviceRoster roster;
39	BPartition* partition;
40	BDiskDevice device;
41
42	status_t status = roster.GetPartitionForPath(argv[1], &device,
43		&partition);
44	if (status != B_OK) {
45		if (strncmp(argv[1], "/dev", 4)) {
46			// try mounted volume
47			status = roster.FindPartitionByMountPoint(argv[1], &device,
48				&partition) ? B_OK : B_BAD_VALUE;
49		}
50
51		// TODO: try to register file device
52
53		if (status != B_OK) {
54			fprintf(stderr, "%s: Failed to get disk device for path \"%s\": "
55				"%s\n", kProgramName, argv[1], strerror(status));
56			return 1;
57		}
58	}
59
60	// Prepare the device for modifications
61
62	status = device.PrepareModifications();
63	if (status != B_OK) {
64		fprintf(stderr, "%s: Could not prepare the device for modifications: "
65			"%s\n", kProgramName, strerror(status));
66		return false;
67	}
68
69	// Check if the partition supports resizing
70
71	bool canResizeWhileMounted;
72	bool canResize = partition->CanResize(NULL, &canResizeWhileMounted);
73
74	if (!canResize && !canResizeWhileMounted) {
75		fprintf(stderr, "%s: The disk system does not support resizing.\n",
76			kProgramName);
77		return 1;
78	}
79
80	if (partition->IsMounted() && !canResizeWhileMounted) {
81		fprintf(stderr, "%s: The disk system does not support resizing a "
82			"mounted volume.\n", kProgramName);
83		return 1;
84	}
85	if (!partition->IsMounted() && !canResize) {
86		fprintf(stderr, "%s: The disk system does not support resizing a "
87			"volume that is not mounted.\n", kProgramName);
88		return 1;
89	}
90
91	// Validate the requested size
92
93	off_t validatedSize = size;
94	status = partition->ValidateResize(&validatedSize);
95	if (status != B_OK) {
96		fprintf(stderr, "%s: Failed to validate the size: %s\n", kProgramName,
97			strerror(status));
98		return 1;
99	}
100
101	if (validatedSize != size) {
102		printf("The requested size (%" B_PRId64 " bytes) was not accepted.\n"
103			"Resize to %" B_PRId64 " bytes instead? (y/N): ", size,
104			(int64)validatedSize);
105
106		int c = getchar();
107		if (c != 'y')
108			return 0;
109	}
110
111	// Resize the volume
112
113	status = partition->Resize(validatedSize);
114	if (status != B_OK) {
115		fprintf(stderr, "%s: Resizing failed: %s\n", kProgramName,
116			strerror(status));
117		return 1;
118	}
119
120	status = device.CommitModifications();
121	if (status != B_OK) {
122		fprintf(stderr, "%s: Failed to commit modifications: %s\n",
123			kProgramName, strerror(status));
124		return 1;
125	}
126
127	return 0;
128}
129