1 /* 2 * Copyright 2013, Ingo Weinhold, ingo_weinhold@gmx.de. 3 * Distributed under the terms of the MIT License. 4 */ 5 6 7 #include "PackageSettings.h" 8 9 #include <driver_settings.h> 10 11 #include <AutoDeleterDrivers.h> 12 #include <directories.h> 13 #include <fs/KPath.h> 14 #include <vfs.h> 15 16 #include "DebugSupport.h" 17 18 19 static const char* const kBlockedEntriesParameterName = "BlockedEntries"; 20 static const char* const kLegacyBlockedEntriesParameterName = "EntryBlacklist"; 21 22 23 // #pragma mark - PackageSettingsItem 24 25 26 PackageSettingsItem::PackageSettingsItem() 27 : 28 fName(), 29 fEntries() 30 { 31 } 32 33 34 PackageSettingsItem::~PackageSettingsItem() 35 { 36 Entry* entry = fEntries.Clear(true); 37 while (entry != NULL) { 38 Entry* next = entry->HashNext(); 39 delete entry; 40 entry = next; 41 } 42 } 43 44 45 status_t 46 PackageSettingsItem::Init(const char* name) 47 { 48 if (!fName.SetTo(name) || fEntries.Init() != B_OK) 49 RETURN_ERROR(B_NO_MEMORY); 50 return B_OK; 51 } 52 53 54 status_t 55 PackageSettingsItem::ApplySettings(const driver_parameter* parameters, 56 int parameterCount) 57 { 58 for (int i = 0; i < parameterCount; i++) { 59 const driver_parameter& subParameter = parameters[i]; 60 if (strcmp(subParameter.name, kBlockedEntriesParameterName) != 0 61 && strcmp(subParameter.name, kLegacyBlockedEntriesParameterName) 62 != 0) 63 continue; 64 65 status_t error = _AddBlockedEntries(subParameter); 66 // abort only in case of serious issues (memory shortage) 67 if (error == B_NO_MEMORY) 68 return error; 69 } 70 71 return B_OK; 72 } 73 74 75 void 76 PackageSettingsItem::AddEntry(Entry* entry) 77 { 78 fEntries.Insert(entry); 79 } 80 81 82 status_t 83 PackageSettingsItem::AddEntry(const char* path, Entry*& _entry) 84 { 85 Entry* parent = NULL; 86 87 while (*path != '\0') { 88 while (*path == '/') { 89 path++; 90 continue; 91 } 92 93 const char* componentEnd = strchr(path, '/'); 94 if (componentEnd == NULL) 95 componentEnd = path + strlen(path); 96 97 String name; 98 if (!name.SetTo(path, componentEnd - path)) 99 RETURN_ERROR(B_NO_MEMORY); 100 101 Entry* entry = FindEntry(parent, name); 102 if (entry == NULL) { 103 entry = new(std::nothrow) Entry(parent, name); 104 if (entry == NULL) 105 RETURN_ERROR(B_NO_MEMORY); 106 AddEntry(entry); 107 } 108 109 path = componentEnd; 110 parent = entry; 111 } 112 113 if (parent == NULL) 114 return B_BAD_VALUE; 115 116 _entry = parent; 117 return B_OK; 118 } 119 120 121 PackageSettingsItem::Entry* 122 PackageSettingsItem::FindEntry(Entry* parent, const String& name) const 123 { 124 return fEntries.Lookup(EntryKey(parent, name)); 125 } 126 127 128 PackageSettingsItem::Entry* 129 PackageSettingsItem::FindEntry(Entry* parent, const char* name) const 130 { 131 return fEntries.Lookup(EntryKey(parent, name)); 132 } 133 134 135 status_t 136 PackageSettingsItem::_AddBlockedEntries(const driver_parameter& parameter) 137 { 138 for (int i = 0; i < parameter.parameter_count; i++) { 139 Entry* entry; 140 status_t error = AddEntry(parameter.parameters[i].name, entry); 141 // abort only in case of serious issues (memory shortage) 142 if (error == B_NO_MEMORY) 143 return error; 144 145 entry->SetBlocked(true); 146 } 147 148 return B_OK; 149 } 150 151 152 // #pragma mark - PackageSettings 153 154 155 PackageSettings::PackageSettings() 156 : 157 fPackageItems() 158 { 159 } 160 161 162 PackageSettings::~PackageSettings() 163 { 164 PackageSettingsItem* item = fPackageItems.Clear(true); 165 while (item != NULL) { 166 PackageSettingsItem* next = item->HashNext(); 167 delete item; 168 item = next; 169 } 170 } 171 172 173 status_t 174 PackageSettings::Load(dev_t mountPointDeviceID, ino_t mountPointNodeID, 175 PackageFSMountType mountType) 176 { 177 status_t error = fPackageItems.Init(); 178 if (error != B_OK) 179 RETURN_ERROR(error); 180 181 // First get the safe mode options. Those apply to the system package. 182 if (mountType == PACKAGE_FS_MOUNT_TYPE_SYSTEM) { 183 void* settingsHandle = load_driver_settings(B_SAFEMODE_DRIVER_SETTINGS); 184 if (settingsHandle != NULL) { 185 if (const driver_settings* settings 186 = get_driver_settings(settingsHandle)) { 187 error = _AddPackageSettingsItem("haiku", settings->parameters, 188 settings->parameter_count); 189 // abort only in case of serious issues (memory shortage) 190 if (error == B_NO_MEMORY) 191 return error; 192 } 193 unload_driver_settings(settingsHandle); 194 } 195 } 196 197 // get the mount point relative settings file path 198 const char* settingsFilePath = mountType == PACKAGE_FS_MOUNT_TYPE_HOME 199 ? &(kUserSettingsGlobalDirectory "/packages") 200 [strlen(kUserConfigDirectory) + 1] 201 : &(kSystemSettingsDirectory "/packages")[strlen(kSystemDirectory) + 1]; 202 203 // get an absolute path 204 KPath path; 205 if (path.InitCheck() != B_OK) 206 RETURN_ERROR(path.InitCheck()); 207 208 error = vfs_entry_ref_to_path(mountPointDeviceID, mountPointNodeID, 209 NULL, true, path.LockBuffer(), path.BufferSize()); 210 if (error != B_OK) 211 return error; 212 path.UnlockBuffer(); 213 214 error = path.Append(settingsFilePath); 215 if (error != B_OK) 216 return error; 217 218 // load the driver settings 219 DriverSettingsUnloader settingsHandle(load_driver_settings(path.Path())); 220 if (!settingsHandle.IsSet()) 221 return B_ENTRY_NOT_FOUND; 222 223 const driver_settings* settings 224 = get_driver_settings(settingsHandle.Get()); 225 for (int i = 0; i < settings->parameter_count; i++) { 226 const driver_parameter& parameter = settings->parameters[i]; 227 if (strcmp(parameter.name, "Package") != 0 228 || parameter.value_count < 1) { 229 continue; 230 } 231 232 error = _AddPackageSettingsItem(parameter.values[0], 233 parameter.parameters, parameter.parameter_count); 234 // abort only in case of serious issues (memory shortage) 235 if (error == B_NO_MEMORY) 236 return error; 237 } 238 239 return B_OK; 240 } 241 242 243 const PackageSettingsItem* 244 PackageSettings::PackageItemFor(const String& name) const 245 { 246 return fPackageItems.Lookup(name); 247 } 248 249 250 status_t 251 PackageSettings::_AddPackageSettingsItem(const char* name, 252 const driver_parameter* parameters, int parameterCount) 253 { 254 // get/create the package item 255 PackageSettingsItem* packageItem = fPackageItems.Lookup(StringKey(name)); 256 if (packageItem == NULL) { 257 packageItem = new(std::nothrow) PackageSettingsItem; 258 if (packageItem == NULL || packageItem->Init(name) != B_OK) { 259 delete packageItem; 260 RETURN_ERROR(B_NO_MEMORY); 261 } 262 263 fPackageItems.Insert(packageItem); 264 } 265 266 // apply the settings 267 return packageItem->ApplySettings(parameters, parameterCount); 268 } 269