1/*
2 * Copyright 2003-2007, Axel Dörfler, axeld@pinc-software.de.
3 * Distributed under the terms of the MIT License.
4 */
5
6
7#include "Handle.h"
8
9#include <boot/platform.h>
10#include <util/kernel_cpp.h>
11
12#include <unistd.h>
13#include <errno.h>
14#include <dirent.h>
15#include <limits.h>
16#include <string.h>
17#include <stdio.h>
18
19
20// we're using some libroot specials
21extern int __libc_argc;
22extern char **__libc_argv;
23extern const char *__progname;
24
25extern bool gShowMenu;
26
27
28static status_t
29get_device(const char *path, Node **_device)
30{
31	Handle *device = new Handle(path);
32	if (device == NULL)
33		return B_NO_MEMORY;
34
35	if (device->InitCheck() != B_OK) {
36		fprintf(stderr, "%s: Could not open image \"%s\": %s\n",
37			__progname, path, strerror(device->InitCheck()));
38
39		delete device;
40		return B_ERROR;
41	}
42
43	*_device = device;
44	return B_OK;
45}
46
47
48static status_t
49add_device(const char *path, NodeList *list)
50{
51	Node *device;
52	status_t status = get_device(path, &device);
53	if (status < B_OK)
54		return status;
55
56	printf("add \"%s\" to list of boot devices\n", path);
57	list->Add(device);
58
59	return B_OK;
60}
61
62
63static status_t
64recursive_add_device(const char *path, NodeList *list)
65{
66	DIR *dir = opendir(path);
67	if (dir == NULL)
68		return errno;
69
70	struct dirent *dirent;
71	while ((dirent = readdir(dir)) != NULL) {
72		// we don't care about names with a leading dot (incl. "." and "..")
73		if (dirent->d_name[0] == '.')
74			continue;
75
76		char nextPath[PATH_MAX];
77		strcpy(nextPath, path);
78		strcat(nextPath, "/");
79		strcat(nextPath, dirent->d_name);
80
81		// Note, this doesn't care about if it's a directory or not!
82		if (!strcmp(dirent->d_name, "raw")
83			&& add_device(nextPath, list) == B_OK)
84			continue;
85
86		recursive_add_device(nextPath, list);
87	}
88	closedir(dir);
89
90	return B_OK;
91}
92
93
94static char *
95get_next_argument(int32 *cookie, bool options)
96{
97	int32 i = *cookie + 1;
98
99	if (i == 1 && !options) {
100		// filter out options at the start
101		while (i < __libc_argc && __libc_argv[i][0] == '-')
102			i++;
103	}
104
105	for (; i < __libc_argc; i++) {
106		// Options come at the start
107		if (options && __libc_argv[i][0] != '-')
108			return NULL;
109
110		*cookie = i;
111		return __libc_argv[i];
112	}
113
114	return NULL;
115}
116
117
118static char *
119get_next_option(int32 *cookie)
120{
121	return get_next_argument(cookie, true);
122}
123
124
125static char *
126get_next_device(int32 *cookie)
127{
128	return get_next_argument(cookie, false);
129}
130
131
132//	#pragma mark -
133
134
135status_t
136platform_add_boot_device(struct stage2_args *args, NodeList *devicesList)
137{
138	// we accept a boot device from the command line
139	status_t status = B_ERROR;
140	Node *device;
141
142	int32 cookie = 0;
143	char *path = get_next_device(&cookie);
144	if (path != NULL)
145		status = get_device(path, &device);
146	else
147		status = get_device("/boot/home/test-file-device", &device);
148
149	if (status == B_OK)
150		devicesList->Add(device);
151
152	return status;
153}
154
155
156status_t
157platform_get_boot_partition(struct stage2_args *args, Node *device,
158	NodeList *list, boot::Partition **_partition)
159{
160	NodeIterator iterator = list->GetIterator();
161	boot::Partition *partition = NULL;
162	while ((partition = (boot::Partition *)iterator.Next()) != NULL) {
163		// just take the first partition
164		*_partition = partition;
165		return B_OK;
166	}
167
168	return B_ENTRY_NOT_FOUND;
169}
170
171
172status_t
173platform_add_block_devices(struct stage2_args *args, NodeList *list)
174{
175	int32 cookie = 0;
176	if (get_next_device(&cookie) != NULL) {
177		// add the devices provided on the command line
178		char *path;
179		while ((path = get_next_device(&cookie)) != NULL)
180			add_device(path, list);
181	}
182
183	bool addDevices = true;
184	bool scsi = true;
185	char *option;
186	cookie = 0;
187	while ((option = get_next_option(&cookie)) != NULL) {
188		if (!strcmp(option, "--no-devices"))
189			addDevices = false;
190		else if (!strcmp(option, "--no-scsi"))
191			scsi = false;
192		else if (!strcmp(option, "--menu"))
193			gShowMenu = true;
194		else {
195			fprintf(stderr, "usage: %s [OPTIONS] [image ...]\n"
196				"  --no-devices\tDon't add real devices from /dev/disk\n"
197				"  --no-scsi\tDon't add SCSI devices (might be problematic with some\n"
198				"\t\tUSB mass storage drivers)\n"
199				"  --menu\tShow boot menu\n", __progname);
200			exit(0);
201		}
202	}
203
204	if (addDevices) {
205		recursive_add_device("/dev/disk/ide", list);
206		recursive_add_device("/dev/disk/virtual", list);
207
208		if (scsi)
209			recursive_add_device("/dev/disk/scsi", list);
210	}
211
212	return B_OK;
213}
214
215
216status_t
217platform_register_boot_device(Node *device)
218{
219	return B_OK;
220}
221