1/*
2 * Copyright 2004-2005, Axel Dörfler, axeld@pinc-software.de. All rights reserved.
3 * Distributed under the terms of the MIT License.
4 */
5
6
7#include "Volume.h"
8
9#include "boot_block.h"
10#include "compat.h"
11
12// the definitions in fsproto.h (included by kprotos.h) and fs_interface.h
13// (included by Volume.h) are not compatible
14#define get_vnode _get_vnode
15#define put_vnode _put_vnode
16#define new_vnode _new_vnode
17#define remove_vnode _remove_vnode
18#define unremove_vnode _unremove_vnode
19#define notify_listener _notify_listener
20#define send_notification _send_notification
21
22#include "kprotos.h"
23
24#include <string.h>
25#include <stdio.h>
26#include <unistd.h>
27#include <ctype.h>
28
29
30// Note: these structures have been stolen from fs_shell/kernel.c.
31//		They shouldn't be used anywhere else
32
33extern vnode_ops fs_entry;
34struct vnode;
35
36struct vnlist {
37	vnode           *head;
38	vnode           *tail;
39	int             num;
40};
41
42struct nspace {
43	nspace_id           nsid;
44	my_dev_t            dev;
45	my_ino_t            ino;
46	fsystem             *fs;
47	vnlist              vnodes;
48	void                *data;
49	vnode				*root;
50	vnode				*mount;
51	nspace				*prev;
52	nspace				*next;
53	char                shutdown;
54};
55
56
57void
58usage(char *programName)
59{
60	fprintf(stderr, "usage: %s [-vn] [-b block-size] device-path volume-name\n"
61		"Creates a new BFS file system on the specified device (or image)\n"
62		"\t-b\tblock size (defaults to 1024)\n"
63		"\t-n\tdisable indices (long option --noindex)\n"
64		"\t-v\tfor verbose output.\n",
65		programName);
66
67	exit(0);
68}
69
70
71int
72main(int argc, char **argv)
73{
74	char *programName = argv[0];
75	if (strrchr(programName, '/'))
76		programName = strrchr(programName, '/') + 1;
77
78	if (argc < 2)
79		usage(programName);
80
81	uint32 blockSize = 1024;
82	uint32 flags = 0;
83	bool verbose = false;
84
85	while (*++argv) {
86		char *arg = *argv;
87		if (*arg == '-') {
88			if (arg[1] == '-') {
89				if (!strcmp(arg, "--noindex"))
90					flags |= VOLUME_NO_INDICES;
91				else
92					usage(programName);
93			}
94
95			while (*++arg && isalpha(*arg)) {
96				switch (*arg) {
97					case 'v':
98						verbose = true;
99						break;
100					case 'b':
101						if (*++argv == NULL || !isdigit(**argv))
102							usage(programName);
103
104						blockSize = atol(*argv);
105						break;
106					case 'n':
107						flags |= VOLUME_NO_INDICES;
108						break;
109				}
110			}
111		}
112		else
113			break;
114	}
115
116	char *deviceName = argv[0];
117	if (deviceName == NULL) {
118		fprintf(stderr, "%s: You must at least specify a device where "
119			"the image is going to be created\n", programName);
120		return -1;
121	}
122
123	char *volumeName = "Unnamed";
124	if (argv[1] != NULL)
125		volumeName = argv[1];
126
127	if (blockSize != 1024 && blockSize != 2048 && blockSize != 4096 && blockSize != 8192) {
128		fprintf(stderr, "%s: valid block sizes are: 1024, 2048, 4096, and 8192\n", programName);
129		return -1;
130	}
131
132	// set up tiny VFS and initialize the device/image
133
134    init_block_cache(4096, 0);
135    init_vnode_layer();
136
137    if (install_file_system(&fs_entry, "bfs", 1, -1) == NULL) {
138        printf("can't install my file system\n");
139        exit(0);
140    }
141
142	struct nspace *mount = (nspace *)malloc(sizeof(nspace));
143	if (add_nspace(mount, NULL, "bfs", -1, -1) < B_OK) {
144		fprintf(stderr, "%s: add mount structure failed\n", programName);
145		return -1;
146	}
147
148	Volume volume(mount->nsid);
149	status_t status = volume.Initialize(deviceName, volumeName, blockSize, flags);
150	if (status < B_OK) {
151		fprintf(stderr, "%s: Initializing volume failed: %s\n", programName, strerror(status));
152		return -1;
153	}
154
155	remove_nspace(mount);
156
157	if (verbose) {
158		disk_super_block super = volume.SuperBlock();
159
160		printf("%s: Disk was initialized successfully.\n", programName);
161		printf("\tname: \"%s\"\n", super.name);
162		printf("\tnum blocks: %Ld\n", super.NumBlocks());
163		printf("\tused blocks: %Ld\n", super.UsedBlocks());
164		printf("\tblock size: %lu bytes\n", super.BlockSize());
165		printf("\tnum allocation groups: %ld\n", super.AllocationGroups());
166		printf("\tallocation group size: %ld blocks\n", 1L << super.AllocationGroupShift());
167		printf("\tlog size: %u blocks\n", super.log_blocks.Length());
168	}
169
170	shutdown_block_cache();
171
172	// make the disk image bootable
173
174	int device = open(deviceName, O_RDWR);
175	if (device < 0) {
176		fprintf(stderr, "%s: Could not make image bootable: %s\n", programName, strerror(errno));
177		return -1;
178	}
179
180	// change BIOS drive and partition offset
181	// ToDo: for now, this will only work for images only
182
183	sBootBlockData1[kBIOSDriveOffset] = 0x80;
184		// for now, this should be replaced by the real thing
185	uint32 *offset = (uint32 *)&sBootBlockData1[kPartitionDataOffset];
186	*offset = 0;
187
188	write_pos(device, 0, sBootBlockData1, kBootBlockData1Size);
189	write_pos(device, kBootBlockData2Offset, sBootBlockData2, kBootBlockData2Size);
190
191	close(device);
192	sync();
193
194	return 0;
195}
196
197