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