xref: /haiku/src/add-ons/kernel/file_systems/userlandfs/kernel_add_on/FileSystemInitializer.cpp (revision 4720c31bb08f5c6d1c8ddb616463c6fba9b350a1)
1 /*
2  * Copyright 2001-2009, Ingo Weinhold, ingo_weinhold@gmx.de.
3  * Distributed under the terms of the MIT License.
4  */
5 
6 #include "FileSystemInitializer.h"
7 
8 #include <new>
9 
10 #include <image.h>
11 #include <OS.h>
12 
13 #include <port.h>
14 #include <team.h>
15 
16 #include "AutoDeleter.h"
17 
18 #include "FileSystem.h"
19 #include "RequestAllocator.h"
20 #include "RequestPort.h"
21 #include "Requests.h"
22 #include "SingleReplyRequestHandler.h"
23 #include "UserlandFSDefs.h"
24 
25 
26 // constructor
27 FileSystemInitializer::FileSystemInitializer(const char* name)
28 	:
29 	Referenceable(false),
30 	fName(name),
31 	fFileSystem(NULL)
32 {
33 	// Note: We don't copy the name. It's only needed in FirstTimeInit() and
34 	// the UserlandFS makes sure it is valid until then.
35 }
36 
37 
38 // destructor
39 FileSystemInitializer::~FileSystemInitializer()
40 {
41 	delete fFileSystem;
42 }
43 
44 
45 // FirstTimeInit
46 status_t
47 FileSystemInitializer::FirstTimeInit()
48 {
49 	// First check whether a server for this FS is already loaded. Look for a
50 	// port with the respective name.
51 	char portName[B_OS_NAME_LENGTH];
52 	snprintf(portName, sizeof(portName), "_userlandfs_%s", fName);
53 
54 	port_id port = find_port(portName);
55 	if (port >= 0)
56 		return _Init(port);
57 
58 	// We have to start the server ourselves. First create the port we're going
59 	// to use.
60 	port = create_port(1, portName);
61 	if (port < 0)
62 		RETURN_ERROR(port);
63 
64 	// prepare the command line arguments
65 	char portID[16];
66 	snprintf(portID, sizeof(portID), "%ld", port);
67 
68 	const char* args[4] = {
69 		"/system/servers/userlandfs_server",
70 		fName,
71 		portID,
72 		NULL
73 	};
74 
75 	// start the server
76 	thread_id thread = load_image_etc(3, args, NULL, B_NORMAL_PRIORITY,
77 		B_SYSTEM_TEAM, 0);
78 	if (thread < 0) {
79 		delete_port(port);
80 		RETURN_ERROR(thread);
81 	}
82 
83 	// let it own the port and start the team
84 	status_t error = set_port_owner(port, thread);
85 	if (error == B_OK)
86 		resume_thread(thread);
87 
88 	// and do the initialization
89 	if (error == B_OK)
90 		error = _Init(port);
91 
92 	if (error != B_OK) {
93 		kill_team(thread);
94 		delete_port(port);
95 		RETURN_ERROR(error);
96 	}
97 
98 	return B_OK;
99 }
100 
101 
102 status_t
103 FileSystemInitializer::_Init(port_id port)
104 {
105 	// allocate a buffer for the FS info
106 	const size_t bufferSize = 1024;
107 	fs_init_info* info = (fs_init_info*)malloc(bufferSize);
108 	MemoryDeleter _(info);
109 
110 	// Read the info -- we peek only, so it won't go away and we can do the
111 	// initialization again, in case we get completely unloaded are reloaded
112 	// later.
113 	ssize_t bytesRead = read_port_etc(port, NULL, info, bufferSize,
114 	    B_PEEK_PORT_MESSAGE | B_CAN_INTERRUPT, 0);
115 	if (bytesRead < 0)
116 		RETURN_ERROR(bytesRead);
117 
118 	// sanity check
119 	if ((size_t)bytesRead < sizeof(fs_init_info)
120 		|| info->portInfoCount < 2
121 		|| (size_t)bytesRead < sizeof(fs_init_info)
122 			+ info->portInfoCount * sizeof(Port::Info)) {
123 		RETURN_ERROR(B_BAD_DATA);
124 	}
125 
126 	// get the port's team
127 	port_info portInfo;
128 	status_t error = get_port_info(port, &portInfo);
129 	if (error != B_OK)
130 		RETURN_ERROR(error);
131 
132 	// create and init the FileSystem
133 	fFileSystem = new(std::nothrow) FileSystem;
134 	if (!fFileSystem)
135 		return B_NO_MEMORY;
136 
137 	error = fFileSystem->Init(fName, portInfo.team, info->portInfos,
138 		info->portInfoCount, info->capabilities);
139 	if (error != B_OK)
140 		RETURN_ERROR(error);
141 
142 	return B_OK;
143 }
144