btrfs: Attempt to fix GCC2 build.
[haiku.git] / src / servers / package / PackageDaemon.cpp
blob6b6e998015af02305b72acfd75ab0147a8059a06
1 /*
2 * Copyright 2013, Haiku, Inc. All Rights Reserved.
3 * Distributed under the terms of the MIT License.
5 * Authors:
6 * Ingo Weinhold <ingo_weinhold@gmx.de>
7 */
10 #include "PackageDaemon.h"
12 #include <errno.h>
13 #include <string.h>
15 #include <Directory.h>
16 #include <NodeMonitor.h>
18 #include <AutoDeleter.h>
19 #include <package/DaemonDefs.h>
21 #include "DebugSupport.h"
22 #include "Root.h"
23 #include "Volume.h"
26 using namespace BPackageKit::BPrivate;
29 PackageDaemon::PackageDaemon(status_t* _error)
31 BServer(B_PACKAGE_DAEMON_APP_SIGNATURE, false, _error),
32 fSystemRoot(NULL),
33 fRoots(10, true),
34 fVolumeWatcher()
39 PackageDaemon::~PackageDaemon()
44 status_t
45 PackageDaemon::Init()
47 status_t error = fVolumeWatcher.StartWatching(BMessenger(this, this));
48 if (error != B_OK) {
49 ERROR("PackageDaemon::Init(): failed to start volume watching: %s\n",
50 strerror(error));
53 // register all packagefs volumes
54 for (int32 cookie = 0;;) {
55 dev_t device = next_dev(&cookie);
56 if (device < 0)
57 break;
59 _RegisterVolume(device);
62 return B_OK;
66 void
67 PackageDaemon::MessageReceived(BMessage* message)
69 switch (message->what) {
70 case B_NODE_MONITOR:
72 int32 opcode;
73 if (message->FindInt32("opcode", &opcode) != B_OK)
74 break;
76 if (opcode == B_DEVICE_MOUNTED)
77 _HandleVolumeMounted(message);
78 else if (opcode == B_DEVICE_UNMOUNTED)
79 _HandleVolumeUnmounted(message);
80 break;
83 case B_MESSAGE_GET_INSTALLATION_LOCATION_INFO:
84 case B_MESSAGE_COMMIT_TRANSACTION:
86 status_t error;
87 node_ref nodeRef;
89 // Get the node_ref of the filesystem root to see which one it is
90 error = message->FindInt32("volume", &nodeRef.device);
91 if (error == B_OK)
92 error = message->FindInt64("root", &nodeRef.node);
94 if (fSystemRoot != NULL && (error != B_OK
95 || fSystemRoot->NodeRef() == nodeRef)) {
96 fSystemRoot->HandleRequest(DetachCurrentMessage());
97 } else if (error == B_OK) {
98 Root* root = _FindRoot(nodeRef);
99 if (root != NULL) {
100 root->HandleRequest(DetachCurrentMessage());
103 break;
106 default:
107 BServer::MessageReceived(message);
108 break;
113 status_t
114 PackageDaemon::_RegisterVolume(dev_t deviceID)
116 // get the FS info and check whether this is a package FS volume at all
117 fs_info info;
118 status_t error = fs_stat_dev(deviceID, &info);
119 if (error != 0)
120 RETURN_ERROR(error);
122 if (strcmp(info.fsh_name, "packagefs") != 0)
123 RETURN_ERROR(B_BAD_VALUE);
125 // create a volume
126 Volume* volume = new(std::nothrow) Volume(this);
127 if (volume == NULL)
128 RETURN_ERROR(B_NO_MEMORY);
129 ObjectDeleter<Volume> volumeDeleter(volume);
131 node_ref rootRef;
132 error = volume->Init(node_ref(info.dev, info.root), rootRef);
133 if (error != B_OK)
134 RETURN_ERROR(error);
136 if (volume->MountType() == PACKAGE_FS_MOUNT_TYPE_CUSTOM) {
137 // TODO: Or maybe not?
138 INFORM("skipping custom mounted volume at \"%s\"\n",
139 volume->Path().String());
140 return B_OK;
143 // get the root for the volume and register it
144 Root* root;
145 error = _GetOrCreateRoot(rootRef, root);
146 if (error != B_OK)
147 RETURN_ERROR(error);
149 error = root->RegisterVolume(volume);
150 if (error != B_OK) {
151 _PutRoot(root);
152 RETURN_ERROR(error);
154 volumeDeleter.Detach();
156 INFORM("volume at \"%s\" registered\n", volume->Path().String());
158 return B_OK;
162 void
163 PackageDaemon::_UnregisterVolume(Volume* volume)
165 volume->Unmounted();
167 INFORM("volume at \"%s\" unregistered\n", volume->Path().String());
169 Root* root = volume->GetRoot();
170 root->UnregisterVolume(volume);
172 _PutRoot(root);
176 status_t
177 PackageDaemon::_GetOrCreateRoot(const node_ref& nodeRef, Root*& _root)
179 Root* root = _FindRoot(nodeRef);
180 if (root != NULL) {
181 root->AcquireReference();
182 } else {
183 root = new(std::nothrow) Root;
184 if (root == NULL)
185 RETURN_ERROR(B_NO_MEMORY);
186 ObjectDeleter<Root> rootDeleter(root);
188 bool isSystemRoot = false;
189 if (fSystemRoot == NULL) {
190 struct stat st;
191 isSystemRoot = stat("/boot", &st) == 0
192 && node_ref(st.st_dev, st.st_ino) == nodeRef;
195 status_t error = root->Init(nodeRef, isSystemRoot);
196 if (error != B_OK)
197 RETURN_ERROR(error);
199 if (!fRoots.AddItem(root))
200 RETURN_ERROR(B_NO_MEMORY);
202 rootDeleter.Detach();
204 if (isSystemRoot)
205 fSystemRoot = root;
207 INFORM("root at \"%s\" (device: %" B_PRIdDEV ", node: %" B_PRIdINO ") "
208 "registered\n", root->Path().String(), nodeRef.device,
209 nodeRef.node);
212 _root = root;
213 return B_OK;
217 Root*
218 PackageDaemon::_FindRoot(const node_ref& nodeRef) const
220 for (int32 i = 0; Root* root = fRoots.ItemAt(i); i++) {
221 if (root->NodeRef() == nodeRef)
222 return root;
225 return NULL;
229 void
230 PackageDaemon::_PutRoot(Root* root)
232 if (root->ReleaseReference() == 1) {
233 INFORM("root at \"%s\" unregistered\n", root->Path().String());
234 fRoots.RemoveItem(root, true);
235 // deletes the object
240 Volume*
241 PackageDaemon::_FindVolume(dev_t deviceID) const
243 for (int32 i = 0; Root* root = fRoots.ItemAt(i); i++) {
244 if (Volume* volume = root->FindVolume(deviceID))
245 return volume;
248 return NULL;
252 void
253 PackageDaemon::_HandleVolumeMounted(const BMessage* message)
255 int32 device;
256 if (message->FindInt32("new device", &device) != B_OK)
257 return;
259 // _RegisterVolume() also checks whether it is a package FS volume, so we
260 // don't need to bother.
261 _RegisterVolume(device);
265 void
266 PackageDaemon::_HandleVolumeUnmounted(const BMessage* message)
268 int32 device;
269 if (message->FindInt32("device", &device) != B_OK)
270 return;
272 if (Volume* volume = _FindVolume(device))
273 _UnregisterVolume(volume);
277 // #pragma mark -
281 main(int argc, const char* const* argv)
283 status_t error;
284 PackageDaemon daemon(&error);
285 if (error == B_OK)
286 error = daemon.Init();
287 if (error != B_OK) {
288 FATAL("failed to init server application: %s\n", strerror(error));
289 return 1;
292 daemon.Run();
293 return 0;