1// kernel_emu.cpp
2
3#include <stdarg.h>
4#include <stdio.h>
5#include <stdlib.h>
6
7#include <fsproto.h>
8#include <KernelExport.h>
9#include <OS.h>
10
11#include "RequestPort.h"
12#include "Requests.h"
13#include "RequestThread.h"
14#include "UserlandFSServer.h"
15#include "UserlandRequestHandler.h"
16
17// Taken from the OBOS Storage Kit (storage_support.cpp)
18/*! The length of the first component is returned as well as the index at
19	which the next one starts. These values are only valid, if the function
20	returns \c B_OK.
21	\param path the path to be parsed
22	\param length the variable the length of the first component is written
23		   into
24	\param nextComponent the variable the index of the next component is
25		   written into. \c 0 is returned, if there is no next component.
26	\return \c B_OK, if \a path is not \c NULL, \c B_BAD_VALUE otherwise
27*/
28static
29status_t
30parse_first_path_component(const char *path, int32& length,
31						   int32& nextComponent)
32{
33	status_t error = (path ? B_OK : B_BAD_VALUE);
34	if (error == B_OK) {
35		int32 i = 0;
36		// find first '/' or end of name
37		for (; path[i] != '/' && path[i] != '\0'; i++);
38		// handle special case "/..." (absolute path)
39		if (i == 0 && path[i] != '\0')
40			i = 1;
41		length = i;
42		// find last '/' or end of name
43		for (; path[i] == '/' && path[i] != '\0'; i++);
44		if (path[i] == '\0')	// this covers "" as well
45			nextComponent = 0;
46		else
47			nextComponent = i;
48	}
49	return error;
50}
51
52// new_path
53int
54new_path(const char *path, char **copy)
55{
56	// check errors and special cases
57	if (!copy)
58		return B_BAD_VALUE;
59	if (!path) {
60		*copy = NULL;
61		return B_OK;
62	}
63	int32 len = strlen(path);
64	if (len < 1)
65		return B_ENTRY_NOT_FOUND;
66	bool appendDot = (path[len - 1] == '/');
67	if (appendDot)
68		len++;
69	if (len >= B_PATH_NAME_LENGTH)
70		return B_NAME_TOO_LONG;
71	// check the path components
72	const char *remainder = path;
73	int32 length, nextComponent;
74	do {
75		status_t error
76			= parse_first_path_component(remainder, length, nextComponent);
77		if (error != B_OK)
78			return error;
79		if (length >= B_FILE_NAME_LENGTH)
80			error = B_NAME_TOO_LONG;
81		remainder += nextComponent;
82	} while (nextComponent != 0);
83	// clone the path
84	char *copiedPath = (char*)malloc(len + 1);
85	if (!copiedPath)
86		return B_NO_MEMORY;
87	strcpy(copiedPath, path);
88	// append a dot, if desired
89	if (appendDot) {
90		copiedPath[len] = '.';
91		copiedPath[len] = '\0';
92	}
93	*copy = copiedPath;
94	return B_OK;
95}
96
97// free_path
98void
99free_path(char *p)
100{
101	free(p);
102}
103
104// #pragma mark -
105
106// get_port_and_fs
107static
108status_t
109get_port_and_fs(RequestPort** port, UserFileSystem** fileSystem)
110{
111	// get the request thread
112	RequestThread* thread = RequestThread::GetCurrentThread();
113	if (thread) {
114		*port = thread->GetPort();
115		*fileSystem = thread->GetFileSystem();
116	} else {
117		*port = UserlandFSServer::GetNotificationRequestPort();
118		*fileSystem = UserlandFSServer::GetFileSystem();
119		if (!*port || !*fileSystem)
120			return B_BAD_VALUE;
121	}
122	return B_OK;
123}
124
125// notify_listener
126int
127notify_listener(int op, nspace_id nsid, vnode_id vnida, vnode_id vnidb,
128	vnode_id vnidc, const char *name)
129{
130	// get the request port and the file system
131	RequestPort* port;
132	UserFileSystem* fileSystem;
133	status_t error = get_port_and_fs(&port, &fileSystem);
134	if (error != B_OK)
135		return error;
136	// prepare the request
137	RequestAllocator allocator(port->GetPort());
138	NotifyListenerRequest* request;
139	error = AllocateRequest(allocator, &request);
140	if (error != B_OK)
141		return error;
142	request->operation = op;
143	request->nsid = nsid;
144	request->vnida = vnida;
145	request->vnidb = vnidb;
146	request->vnidc = vnidc;
147	error = allocator.AllocateString(request->name, name);
148	if (error != B_OK)
149		return error;
150	// send the request
151	UserlandRequestHandler handler(fileSystem, NOTIFY_LISTENER_REPLY);
152	NotifyListenerReply* reply;
153	error = port->SendRequest(&allocator, &handler, (Request**)&reply);
154	if (error != B_OK)
155		return error;
156	RequestReleaser requestReleaser(port, reply);
157	// process the reply
158	if (reply->error != B_OK)
159		return reply->error;
160	return error;
161}
162
163// notify_select_event
164void
165notify_select_event(selectsync *sync, uint32 ref)
166{
167	// get the request port and the file system
168	RequestPort* port;
169	UserFileSystem* fileSystem;
170	status_t error = get_port_and_fs(&port, &fileSystem);
171	if (error != B_OK)
172		return;
173	// prepare the request
174	RequestAllocator allocator(port->GetPort());
175	NotifySelectEventRequest* request;
176	error = AllocateRequest(allocator, &request);
177	if (error != B_OK)
178		return;
179	request->sync = sync;
180	request->ref = ref;
181	// send the request
182	UserlandRequestHandler handler(fileSystem, NOTIFY_SELECT_EVENT_REPLY);
183	NotifySelectEventReply* reply;
184	error = port->SendRequest(&allocator, &handler, (Request**)&reply);
185	if (error != B_OK)
186		return;
187	RequestReleaser requestReleaser(port, reply);
188	// process the reply: nothing to do
189}
190
191// send_notification
192int
193send_notification(port_id targetPort, long token, ulong what, long op,
194	nspace_id nsida, nspace_id nsidb, vnode_id vnida, vnode_id vnidb,
195	vnode_id vnidc, const char *name)
196{
197	// get the request port and the file system
198	RequestPort* port;
199	UserFileSystem* fileSystem;
200	status_t error = get_port_and_fs(&port, &fileSystem);
201	if (error != B_OK)
202		return error;
203	// prepare the request
204	RequestAllocator allocator(port->GetPort());
205	SendNotificationRequest* request;
206	error = AllocateRequest(allocator, &request);
207	if (error != B_OK)
208		return error;
209	request->port = targetPort;
210	request->token = token;
211	request->what = what;
212	request->operation = op;
213	request->nsida = nsida;
214	request->nsidb = nsidb;
215	request->vnida = vnida;
216	request->vnidb = vnidb;
217	request->vnidc = vnidc;
218	error = allocator.AllocateString(request->name, name);
219	if (error != B_OK)
220		return error;
221	// send the request
222	UserlandRequestHandler handler(fileSystem, SEND_NOTIFICATION_REPLY);
223	SendNotificationReply* reply;
224	error = port->SendRequest(&allocator, &handler, (Request**)&reply);
225	if (error != B_OK)
226		return error;
227	RequestReleaser requestReleaser(port, reply);
228	// process the reply
229	if (reply->error != B_OK)
230		return reply->error;
231	return error;
232}
233
234// #pragma mark -
235
236// get_vnode
237_EXPORT
238int
239get_vnode(nspace_id nsid, vnode_id vnid, void** data)
240{
241	// get the request port and the file system
242	RequestPort* port;
243	UserFileSystem* fileSystem;
244	status_t error = get_port_and_fs(&port, &fileSystem);
245	if (error != B_OK)
246		return error;
247	// prepare the request
248	RequestAllocator allocator(port->GetPort());
249	GetVNodeRequest* request;
250	error = AllocateRequest(allocator, &request);
251	if (error != B_OK)
252		return error;
253	request->nsid = nsid;
254	request->vnid = vnid;
255	// send the request
256	UserlandRequestHandler handler(fileSystem, GET_VNODE_REPLY);
257	GetVNodeReply* reply;
258	error = port->SendRequest(&allocator, &handler, (Request**)&reply);
259	if (error != B_OK)
260		return error;
261	RequestReleaser requestReleaser(port, reply);
262	// process the reply
263	if (reply->error != B_OK)
264		return reply->error;
265	*data = reply->node;
266	return error;
267}
268
269// put_vnode
270_EXPORT
271int
272put_vnode(nspace_id nsid, vnode_id vnid)
273{
274	// get the request port and the file system
275	RequestPort* port;
276	UserFileSystem* fileSystem;
277	status_t error = get_port_and_fs(&port, &fileSystem);
278	if (error != B_OK)
279		return error;
280	// prepare the request
281	RequestAllocator allocator(port->GetPort());
282	PutVNodeRequest* request;
283	error = AllocateRequest(allocator, &request);
284	if (error != B_OK)
285		return error;
286	request->nsid = nsid;
287	request->vnid = vnid;
288	// send the request
289	UserlandRequestHandler handler(fileSystem, PUT_VNODE_REPLY);
290	PutVNodeReply* reply;
291	error = port->SendRequest(&allocator, &handler, (Request**)&reply);
292	if (error != B_OK)
293		return error;
294	RequestReleaser requestReleaser(port, reply);
295	// process the reply
296	if (reply->error != B_OK)
297		return reply->error;
298	return error;
299}
300
301// new_vnode
302_EXPORT
303int
304new_vnode(nspace_id nsid, vnode_id vnid, void* data)
305{
306	// get the request port and the file system
307	RequestPort* port;
308	UserFileSystem* fileSystem;
309	status_t error = get_port_and_fs(&port, &fileSystem);
310	if (error != B_OK)
311		return error;
312	// prepare the request
313	RequestAllocator allocator(port->GetPort());
314	NewVNodeRequest* request;
315	error = AllocateRequest(allocator, &request);
316	if (error != B_OK)
317		return error;
318	request->nsid = nsid;
319	request->vnid = vnid;
320	request->node = data;
321	// send the request
322	UserlandRequestHandler handler(fileSystem, NEW_VNODE_REPLY);
323	NewVNodeReply* reply;
324	error = port->SendRequest(&allocator, &handler, (Request**)&reply);
325	if (error != B_OK)
326		return error;
327	RequestReleaser requestReleaser(port, reply);
328	// process the reply
329	if (reply->error != B_OK)
330		return reply->error;
331	return error;
332}
333
334// remove_vnode
335_EXPORT
336int
337remove_vnode(nspace_id nsid, vnode_id vnid)
338{
339	// get the request port and the file system
340	RequestPort* port;
341	UserFileSystem* fileSystem;
342	status_t error = get_port_and_fs(&port, &fileSystem);
343	if (error != B_OK)
344		return error;
345	// prepare the request
346	RequestAllocator allocator(port->GetPort());
347	RemoveVNodeRequest* request;
348	error = AllocateRequest(allocator, &request);
349	if (error != B_OK)
350		return error;
351	request->nsid = nsid;
352	request->vnid = vnid;
353	// send the request
354	UserlandRequestHandler handler(fileSystem, REMOVE_VNODE_REPLY);
355	RemoveVNodeReply* reply;
356	error = port->SendRequest(&allocator, &handler, (Request**)&reply);
357	if (error != B_OK)
358		return error;
359	RequestReleaser requestReleaser(port, reply);
360	// process the reply
361	if (reply->error != B_OK)
362		return reply->error;
363	return error;
364}
365
366// unremove_vnode
367_EXPORT
368int
369unremove_vnode(nspace_id nsid, vnode_id vnid)
370{
371	// get the request port and the file system
372	RequestPort* port;
373	UserFileSystem* fileSystem;
374	status_t error = get_port_and_fs(&port, &fileSystem);
375	if (error != B_OK)
376		return error;
377	// prepare the request
378	RequestAllocator allocator(port->GetPort());
379	UnremoveVNodeRequest* request;
380	error = AllocateRequest(allocator, &request);
381	if (error != B_OK)
382		return error;
383	request->nsid = nsid;
384	request->vnid = vnid;
385	// send the request
386	UserlandRequestHandler handler(fileSystem, UNREMOVE_VNODE_REPLY);
387	UnremoveVNodeReply* reply;
388	error = port->SendRequest(&allocator, &handler, (Request**)&reply);
389	if (error != B_OK)
390		return error;
391	RequestReleaser requestReleaser(port, reply);
392	// process the reply
393	if (reply->error != B_OK)
394		return reply->error;
395	return error;
396}
397
398// is_vnode_removed
399_EXPORT
400int
401is_vnode_removed(nspace_id nsid, vnode_id vnid)
402{
403	// get the request port and the file system
404	RequestPort* port;
405	UserFileSystem* fileSystem;
406	status_t error = get_port_and_fs(&port, &fileSystem);
407	if (error != B_OK)
408		return error;
409	// prepare the request
410	RequestAllocator allocator(port->GetPort());
411	IsVNodeRemovedRequest* request;
412	error = AllocateRequest(allocator, &request);
413	if (error != B_OK)
414		return error;
415	request->nsid = nsid;
416	request->vnid = vnid;
417	// send the request
418	UserlandRequestHandler handler(fileSystem, IS_VNODE_REMOVED_REPLY);
419	IsVNodeRemovedReply* reply;
420	error = port->SendRequest(&allocator, &handler, (Request**)&reply);
421	if (error != B_OK)
422		return error;
423	RequestReleaser requestReleaser(port, reply);
424	// process the reply
425	if (reply->error != B_OK)
426		return reply->error;
427	return reply->result;
428}
429
430// #pragma mark -
431
432// kernel_debugger
433_EXPORT
434void
435kernel_debugger(const char *message)
436{
437	debugger(message);
438}
439
440// panic
441_EXPORT
442void
443panic(const char *format, ...)
444{
445	char buffer[1024];
446	strcpy(buffer, "PANIC: ");
447	int32 prefixLen = strlen(buffer);
448	int bufferSize = sizeof(buffer) - prefixLen;
449	va_list args;
450	va_start(args, format);
451	// no vsnprintf() on PPC
452	#if defined(__INTEL__)
453		vsnprintf(buffer + prefixLen, bufferSize - 1, format, args);
454	#else
455		vsprintf(buffer + prefixLen, format, args);
456	#endif
457	va_end(args);
458	buffer[sizeof(buffer) - 1] = '\0';
459	debugger(buffer);
460}
461
462// parse_expression
463_EXPORT
464ulong
465parse_expression(char *str)
466{
467	return 0;
468}
469
470// add_debugger_command
471_EXPORT
472int
473add_debugger_command(char *name, int (*func)(int argc, char **argv),
474	char *help)
475{
476	return B_OK;
477}
478
479// remove_debugger_command
480_EXPORT
481int
482remove_debugger_command(char *name, int (*func)(int argc, char **argv))
483{
484	return B_OK;
485}
486
487// kprintf
488_EXPORT
489void
490kprintf(const char *format, ...)
491{
492}
493
494// spawn_kernel_thread
495thread_id
496spawn_kernel_thread(thread_entry function, const char *threadName,
497	long priority, void *arg)
498{
499	return spawn_thread(function, threadName, priority, arg);
500}
501
502