1 /* 2 * Copyright 2013, Haiku, Inc. All Rights Reserved. 3 * Distributed under the terms of the MIT License. 4 * 5 * Authors: 6 * Ingo Weinhold <ingo_weinhold@gmx.de> 7 */ 8 9 10 #include "PackageDaemon.h" 11 12 #include <errno.h> 13 #include <string.h> 14 15 #include <Directory.h> 16 #include <NodeMonitor.h> 17 18 #include <AutoDeleter.h> 19 #include <package/DaemonDefs.h> 20 21 #include "DebugSupport.h" 22 #include "Root.h" 23 #include "Volume.h" 24 25 26 using namespace BPackageKit::BPrivate; 27 28 29 PackageDaemon::PackageDaemon(status_t* _error) 30 : 31 BServer(B_PACKAGE_DAEMON_APP_SIGNATURE, false, _error), 32 fSystemRoot(NULL), 33 fRoots(10, true), 34 fVolumeWatcher() 35 { 36 } 37 38 39 PackageDaemon::~PackageDaemon() 40 { 41 } 42 43 44 status_t 45 PackageDaemon::Init() 46 { 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)); 51 } 52 53 // register all packagefs volumes 54 for (int32 cookie = 0;;) { 55 dev_t device = next_dev(&cookie); 56 if (device < 0) 57 break; 58 59 _RegisterVolume(device); 60 } 61 62 return B_OK; 63 } 64 65 66 void 67 PackageDaemon::MessageReceived(BMessage* message) 68 { 69 switch (message->what) { 70 case B_NODE_MONITOR: 71 { 72 int32 opcode; 73 if (message->FindInt32("opcode", &opcode) != B_OK) 74 break; 75 76 if (opcode == B_DEVICE_MOUNTED) 77 _HandleVolumeMounted(message); 78 else if (opcode == B_DEVICE_UNMOUNTED) 79 _HandleVolumeUnmounted(message); 80 break; 81 } 82 83 case B_MESSAGE_GET_INSTALLATION_LOCATION_INFO: 84 case B_MESSAGE_COMMIT_TRANSACTION: 85 { 86 status_t error; 87 node_ref nodeRef; 88 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); 93 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()); 101 } 102 } 103 break; 104 } 105 106 default: 107 BServer::MessageReceived(message); 108 break; 109 } 110 } 111 112 113 status_t 114 PackageDaemon::_RegisterVolume(dev_t deviceID) 115 { 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); 121 122 if (strcmp(info.fsh_name, "packagefs") != 0) 123 RETURN_ERROR(B_BAD_VALUE); 124 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); 130 131 node_ref rootRef; 132 error = volume->Init(node_ref(info.dev, info.root), rootRef); 133 if (error != B_OK) 134 RETURN_ERROR(error); 135 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; 141 } 142 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); 148 149 error = root->RegisterVolume(volume); 150 if (error != B_OK) { 151 _PutRoot(root); 152 RETURN_ERROR(error); 153 } 154 volumeDeleter.Detach(); 155 156 INFORM("volume at \"%s\" registered\n", volume->Path().String()); 157 158 return B_OK; 159 } 160 161 162 void 163 PackageDaemon::_UnregisterVolume(Volume* volume) 164 { 165 volume->Unmounted(); 166 167 INFORM("volume at \"%s\" unregistered\n", volume->Path().String()); 168 169 Root* root = volume->GetRoot(); 170 root->UnregisterVolume(volume); 171 172 _PutRoot(root); 173 } 174 175 176 status_t 177 PackageDaemon::_GetOrCreateRoot(const node_ref& nodeRef, Root*& _root) 178 { 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); 187 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; 193 } 194 195 status_t error = root->Init(nodeRef, isSystemRoot); 196 if (error != B_OK) 197 RETURN_ERROR(error); 198 199 if (!fRoots.AddItem(root)) 200 RETURN_ERROR(B_NO_MEMORY); 201 202 rootDeleter.Detach(); 203 204 if (isSystemRoot) 205 fSystemRoot = root; 206 207 INFORM("root at \"%s\" (device: %" B_PRIdDEV ", node: %" B_PRIdINO ") " 208 "registered\n", root->Path().String(), nodeRef.device, 209 nodeRef.node); 210 } 211 212 _root = root; 213 return B_OK; 214 } 215 216 217 Root* 218 PackageDaemon::_FindRoot(const node_ref& nodeRef) const 219 { 220 for (int32 i = 0; Root* root = fRoots.ItemAt(i); i++) { 221 if (root->NodeRef() == nodeRef) 222 return root; 223 } 224 225 return NULL; 226 } 227 228 229 void 230 PackageDaemon::_PutRoot(Root* root) 231 { 232 if (root->ReleaseReference() == 1) { 233 INFORM("root at \"%s\" unregistered\n", root->Path().String()); 234 fRoots.RemoveItem(root, true); 235 // deletes the object 236 } 237 } 238 239 240 Volume* 241 PackageDaemon::_FindVolume(dev_t deviceID) const 242 { 243 for (int32 i = 0; Root* root = fRoots.ItemAt(i); i++) { 244 if (Volume* volume = root->FindVolume(deviceID)) 245 return volume; 246 } 247 248 return NULL; 249 } 250 251 252 void 253 PackageDaemon::_HandleVolumeMounted(const BMessage* message) 254 { 255 int32 device; 256 if (message->FindInt32("new device", &device) != B_OK) 257 return; 258 259 // _RegisterVolume() also checks whether it is a package FS volume, so we 260 // don't need to bother. 261 _RegisterVolume(device); 262 } 263 264 265 void 266 PackageDaemon::_HandleVolumeUnmounted(const BMessage* message) 267 { 268 int32 device; 269 if (message->FindInt32("device", &device) != B_OK) 270 return; 271 272 if (Volume* volume = _FindVolume(device)) 273 _UnregisterVolume(volume); 274 } 275 276 277 // #pragma mark - 278 279 280 int 281 main(int argc, const char* const* argv) 282 { 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; 290 } 291 292 daemon.Run(); 293 return 0; 294 } 295