1 /*
2 // Copyright (c) 2018 Intel Corporation
3 //
4 // Licensed under the Apache License, Version 2.0 (the "License");
5 // you may not use this file except in compliance with the License.
6 // You may obtain a copy of the License at
7 //
8 // http://www.apache.org/licenses/LICENSE-2.0
9 //
10 // Unless required by applicable law or agreed to in writing, software
11 // distributed under the License is distributed on an "AS IS" BASIS,
12 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 // See the License for the specific language governing permissions and
14 // limitations under the License.
15 */
16 #include "srvcfg_manager.hpp"
17
18 #include <boost/asio/detached.hpp>
19 #include <boost/asio/spawn.hpp>
20 #ifdef USB_CODE_UPDATE
21 #include <cereal/archives/json.hpp>
22 #include <cereal/types/tuple.hpp>
23 #include <cereal/types/unordered_map.hpp>
24
25 #include <cstdio>
26 #endif
27 #include <fstream>
28 #ifdef PERSIST_SETTINGS
29 #include <nlohmann/json.hpp>
30 #endif
31 #include <regex>
32
33 extern std::unique_ptr<boost::asio::steady_timer> timer;
34 extern std::map<std::string, std::shared_ptr<phosphor::service::ServiceConfig>>
35 srvMgrObjects;
36 static bool updateInProgress = false;
37
38 namespace phosphor
39 {
40 namespace service
41 {
42
43 static constexpr const char* overrideConfFileName = "override.conf";
44 static constexpr const size_t restartTimeout = 15; // seconds
45
46 static constexpr const char* systemdOverrideUnitBasePath =
47 "/etc/systemd/system/";
48
49 #ifdef PERSIST_SETTINGS
50 static constexpr const char* persistDataFileVersionStr = "Version";
51 static constexpr const size_t persistDataFileVersion = 1;
52 #endif
53
54 #ifdef USB_CODE_UPDATE
55 static constexpr const char* usbCodeUpdateStateFilePath =
56 "/var/lib/srvcfg_manager";
57 static constexpr const char* usbCodeUpdateStateFile =
58 "/var/lib/srvcfg_manager/usb-code-update-state";
59 static constexpr const char* emptyUsbCodeUpdateRulesFile =
60 "/etc/udev/rules.d/70-bmc-usb.rules";
61
62 using UsbCodeUpdateStateMap = std::unordered_map<std::string, bool>;
63
setUSBCodeUpdateState(const bool & state)64 void ServiceConfig::setUSBCodeUpdateState(const bool& state)
65 {
66 // Enable usb code update
67 if (state)
68 {
69 if (std::filesystem::exists(emptyUsbCodeUpdateRulesFile))
70 {
71 lg2::info("Enable usb code update");
72 std::filesystem::remove(emptyUsbCodeUpdateRulesFile);
73 }
74 return;
75 }
76
77 // Disable usb code update
78 if (std::filesystem::exists(emptyUsbCodeUpdateRulesFile))
79 {
80 std::filesystem::remove(emptyUsbCodeUpdateRulesFile);
81 }
82 std::error_code ec;
83 std::filesystem::create_symlink("/dev/null", emptyUsbCodeUpdateRulesFile,
84 ec);
85 if (ec)
86 {
87 lg2::error("Disable usb code update failed");
88 return;
89 }
90 lg2::info("Disable usb code update");
91 }
92
saveUSBCodeUpdateStateToFile(const bool & maskedState,const bool & enabledState)93 void ServiceConfig::saveUSBCodeUpdateStateToFile(const bool& maskedState,
94 const bool& enabledState)
95 {
96 if (!std::filesystem::exists(usbCodeUpdateStateFilePath))
97 {
98 std::filesystem::create_directories(usbCodeUpdateStateFilePath);
99 }
100
101 UsbCodeUpdateStateMap usbCodeUpdateState;
102 usbCodeUpdateState[srvCfgPropMasked] = maskedState;
103 usbCodeUpdateState[srvCfgPropEnabled] = enabledState;
104
105 std::ofstream file(usbCodeUpdateStateFile, std::ios::out);
106 cereal::JSONOutputArchive archive(file);
107 archive(CEREAL_NVP(usbCodeUpdateState));
108 }
109
getUSBCodeUpdateStateFromFile()110 void ServiceConfig::getUSBCodeUpdateStateFromFile()
111 {
112 if (!std::filesystem::exists(usbCodeUpdateStateFile))
113 {
114 lg2::info("usb-code-update-state file does not exist");
115
116 unitMaskedState = false;
117 unitEnabledState = true;
118 unitRunningState = true;
119 setUSBCodeUpdateState(unitEnabledState);
120 return;
121 }
122
123 std::ifstream file(usbCodeUpdateStateFile);
124 cereal::JSONInputArchive archive(file);
125 UsbCodeUpdateStateMap usbCodeUpdateState;
126 archive(usbCodeUpdateState);
127
128 auto iterMask = usbCodeUpdateState.find(srvCfgPropMasked);
129 if (iterMask != usbCodeUpdateState.end())
130 {
131 unitMaskedState = iterMask->second;
132 if (unitMaskedState)
133 {
134 unitEnabledState = !unitMaskedState;
135 unitRunningState = !unitMaskedState;
136 setUSBCodeUpdateState(unitEnabledState);
137 return;
138 }
139
140 auto iterEnable = usbCodeUpdateState.find(srvCfgPropEnabled);
141 if (iterEnable != usbCodeUpdateState.end())
142 {
143 unitEnabledState = iterEnable->second;
144 unitRunningState = iterEnable->second;
145 setUSBCodeUpdateState(unitEnabledState);
146 }
147 }
148 }
149 #endif
150
updateSocketProperties(const boost::container::flat_map<std::string,VariantType> & propertyMap)151 void ServiceConfig::updateSocketProperties(
152 const boost::container::flat_map<std::string, VariantType>& propertyMap)
153 {
154 auto listenIt = propertyMap.find("Listen");
155 if (listenIt != propertyMap.end())
156 {
157 auto listenVal =
158 std::get<std::vector<std::tuple<std::string, std::string>>>(
159 listenIt->second);
160 if (listenVal.size())
161 {
162 protocol = std::get<0>(listenVal[0]);
163 std::string port = std::get<1>(listenVal[0]);
164 auto tmp = std::stoul(port.substr(port.find_last_of(":") + 1),
165 nullptr, 10);
166 if (tmp > std::numeric_limits<uint16_t>::max())
167 {
168 throw std::out_of_range("Out of range");
169 }
170 portNum = tmp;
171 if (sockAttrIface && sockAttrIface->is_initialized())
172 {
173 internalSet = true;
174 sockAttrIface->set_property(sockAttrPropPort, portNum);
175 internalSet = false;
176 }
177 }
178 }
179 }
180
updateServiceProperties(const boost::container::flat_map<std::string,VariantType> & propertyMap)181 void ServiceConfig::updateServiceProperties(
182 const boost::container::flat_map<std::string, VariantType>& propertyMap)
183 {
184 auto stateIt = propertyMap.find("UnitFileState");
185 if (stateIt != propertyMap.end())
186 {
187 stateValue = std::get<std::string>(stateIt->second);
188 unitEnabledState = unitMaskedState = false;
189 if (stateValue == stateMasked)
190 {
191 unitMaskedState = true;
192 }
193 else if (stateValue == stateEnabled)
194 {
195 unitEnabledState = true;
196 }
197 if (srvCfgIface && srvCfgIface->is_initialized())
198 {
199 internalSet = true;
200 srvCfgIface->set_property(srvCfgPropMasked, unitMaskedState);
201 srvCfgIface->set_property(srvCfgPropEnabled, unitEnabledState);
202 internalSet = false;
203 }
204 }
205 auto subStateIt = propertyMap.find("SubState");
206 if (subStateIt != propertyMap.end())
207 {
208 subStateValue = std::get<std::string>(subStateIt->second);
209 if (subStateValue == subStateRunning ||
210 subStateValue == subStateListening)
211 {
212 unitRunningState = true;
213 }
214 if (srvCfgIface && srvCfgIface->is_initialized())
215 {
216 internalSet = true;
217 srvCfgIface->set_property(srvCfgPropRunning, unitRunningState);
218 internalSet = false;
219 }
220 }
221
222 #ifdef USB_CODE_UPDATE
223 if (baseUnitName == usbCodeUpdateUnitName)
224 {
225 getUSBCodeUpdateStateFromFile();
226 }
227 #endif
228 }
229
queryAndUpdateProperties(bool isStartup=false)230 void ServiceConfig::queryAndUpdateProperties(bool isStartup = false)
231 {
232 std::string objectPath =
233 isSocketActivatedService ? socketObjectPath : serviceObjectPath;
234 if (objectPath.empty())
235 {
236 return;
237 }
238
239 conn->async_method_call(
240 [this,
241 isStartup](boost::system::error_code ec,
242 const boost::container::flat_map<std::string, VariantType>&
243 propertyMap) {
244 if (ec)
245 {
246 lg2::error(
247 "async_method_call error: Failed to service unit properties: {EC}",
248 "EC", ec.value());
249 return;
250 }
251 try
252 {
253 updateServiceProperties(propertyMap);
254 if (!socketObjectPath.empty())
255 {
256 conn->async_method_call(
257 [this](boost::system::error_code ec,
258 const boost::container::flat_map<
259 std::string, VariantType>& propertyMap) {
260 if (ec)
261 {
262 lg2::error(
263 "async_method_call error: Failed to get all property: {EC}",
264 "EC", ec.value());
265 return;
266 }
267 try
268 {
269 updateSocketProperties(propertyMap);
270 if (!srvCfgIface)
271 {
272 registerProperties();
273 }
274 }
275 catch (const std::exception& e)
276 {
277 lg2::error(
278 "Exception in getting socket properties: {ERROR}",
279 "ERROR", e);
280 return;
281 }
282 },
283 sysdService, socketObjectPath, dBusPropIntf,
284 dBusGetAllMethod, sysdSocketIntf);
285 }
286 else if (!srvCfgIface)
287 {
288 registerProperties();
289 }
290 if (isStartup)
291 {
292 // On startup, load our persistent settings and compare to
293 // what was read from systemd. If they are different, use
294 // the persistent settings
295 loadStateFile();
296 }
297 else
298 {
299 // This is just an update once we're already running so
300 // write the values out to our persistent settings
301 writeStateFile();
302 }
303 }
304 catch (const std::exception& e)
305 {
306 lg2::error("Exception in getting socket properties: {ERROR}",
307 "ERROR", e);
308 return;
309 }
310 },
311 sysdService, objectPath, dBusPropIntf, dBusGetAllMethod, sysdUnitIntf);
312 return;
313 }
314
createSocketOverrideConf()315 void ServiceConfig::createSocketOverrideConf()
316 {
317 if (!socketObjectPath.empty())
318 {
319 std::string socketUnitName(instantiatedUnitName + ".socket");
320 /// Check override socket directory exist, if not create it.
321 std::filesystem::path ovrUnitFileDir(systemdOverrideUnitBasePath);
322 ovrUnitFileDir += socketUnitName;
323 ovrUnitFileDir += ".d";
324 if (!std::filesystem::exists(ovrUnitFileDir))
325 {
326 if (!std::filesystem::create_directories(ovrUnitFileDir))
327 {
328 lg2::error("Unable to create the {DIR} directory.", "DIR",
329 ovrUnitFileDir);
330 phosphor::logging::elog<sdbusplus::xyz::openbmc_project::
331 Common::Error::InternalFailure>();
332 }
333 }
334 overrideConfDir = std::string(ovrUnitFileDir);
335 }
336 }
337
writeStateFile()338 void ServiceConfig::writeStateFile()
339 {
340 #ifdef PERSIST_SETTINGS
341 lg2::debug("Writing Persistent State File Information to {STATE_FILE}",
342 "STATE_FILE", stateFile);
343 nlohmann::json stateMap;
344 stateMap[persistDataFileVersionStr] = persistDataFileVersion;
345 stateMap[srvCfgPropMasked] = unitMaskedState;
346 stateMap[srvCfgPropEnabled] = unitEnabledState;
347 stateMap[srvCfgPropRunning] = unitRunningState;
348
349 std::ofstream file(stateFile);
350 file << stateMap;
351 file.close();
352 #endif
353 }
354
loadStateFile()355 void ServiceConfig::loadStateFile()
356 {
357 #ifdef PERSIST_SETTINGS
358 lg2::debug("Loading Persistent State File Information from {STATE_FILE}",
359 "STATE_FILE", stateFile);
360 if (std::filesystem::exists(stateFile))
361 {
362 std::ifstream file(stateFile);
363 if (!file.good())
364 {
365 lg2::error("Error reading {FILEPATH}; delete it and continue",
366 "FILEPATH", stateFile);
367 std::filesystem::remove(stateFile);
368 // rewrite file with what was ready from systemd
369 writeStateFile();
370 return;
371 }
372
373 nlohmann::json stateMap =
374 nlohmann::json::parse(file, nullptr, false, true);
375 if (stateMap.is_discarded())
376 {
377 lg2::error("Error loading {FILEPATH}; delete it and continue",
378 "FILEPATH", stateFile);
379 std::filesystem::remove(stateFile);
380 // rewrite file with what was ready from systemd
381 writeStateFile();
382 return;
383 }
384 else if (stateMap[persistDataFileVersionStr] != persistDataFileVersion)
385 {
386 lg2::error(
387 "Error version:{VERSION} read from {FILEPATH} does not match expected {VERSION_EXP}; delete it and continue",
388 "VERSION", stateMap[persistDataFileVersionStr], "FILEPATH",
389 stateFile, "VERSION_EXP", persistDataFileVersion);
390 std::filesystem::remove(stateFile);
391 // rewrite file with what was ready from systemd
392 writeStateFile();
393 return;
394 }
395
396 // If there are any differences, the persistent config file wins so
397 // update the dbus properties and trigger a reload to apply the changes
398 if (stateMap[srvCfgPropMasked] != unitMaskedState)
399 {
400 lg2::info(
401 "Masked property for {FILEPATH} not equal. Setting to {SETTING}",
402 "FILEPATH", stateFile, "SETTING", stateMap[srvCfgPropMasked]);
403 unitMaskedState = stateMap[srvCfgPropMasked];
404 updatedFlag |=
405 (1 << static_cast<uint8_t>(UpdatedProp::maskedState));
406 startServiceRestartTimer();
407 }
408 if (stateMap[srvCfgPropEnabled] != unitEnabledState)
409 {
410 lg2::info(
411 "Enabled property for {FILEPATH} not equal. Setting to {SETTING}",
412 "FILEPATH", stateFile, "SETTING", stateMap[srvCfgPropEnabled]);
413 unitEnabledState = stateMap[srvCfgPropEnabled];
414 updatedFlag |=
415 (1 << static_cast<uint8_t>(UpdatedProp::enabledState));
416 startServiceRestartTimer();
417 }
418 if (stateMap[srvCfgPropRunning] != unitRunningState)
419 {
420 lg2::info(
421 "Running property for {FILEPATH} not equal. Setting to {SETTING}",
422 "FILEPATH", stateFile, "SETTING", stateMap[srvCfgPropRunning]);
423 unitRunningState = stateMap[srvCfgPropRunning];
424 updatedFlag |=
425 (1 << static_cast<uint8_t>(UpdatedProp::runningState));
426 startServiceRestartTimer();
427 }
428 }
429 else
430 {
431 // Just write out what we got from systemd if no existing config file
432 writeStateFile();
433 }
434 #endif
435 }
436
ServiceConfig(sdbusplus::asio::object_server & srv_,std::shared_ptr<sdbusplus::asio::connection> & conn_,const std::string & objPath_,const std::string & baseUnitName_,const std::string & instanceName_,const std::string & serviceObjPath_,const std::string & socketObjPath_)437 ServiceConfig::ServiceConfig(
438 sdbusplus::asio::object_server& srv_,
439 std::shared_ptr<sdbusplus::asio::connection>& conn_,
440 const std::string& objPath_, const std::string& baseUnitName_,
441 const std::string& instanceName_, const std::string& serviceObjPath_,
442 const std::string& socketObjPath_) :
443 conn(conn_), server(srv_), objPath(objPath_), baseUnitName(baseUnitName_),
444 instanceName(instanceName_), serviceObjectPath(serviceObjPath_),
445 socketObjectPath(socketObjPath_)
446 {
447 isSocketActivatedService = serviceObjectPath.empty();
448 instantiatedUnitName = baseUnitName + addInstanceName(instanceName, "@");
449 updatedFlag = 0;
450 stateFile = srvDataBaseDir + instantiatedUnitName;
451 queryAndUpdateProperties(true);
452 return;
453 }
454
getSocketUnitName()455 std::string ServiceConfig::getSocketUnitName()
456 {
457 return instantiatedUnitName + ".socket";
458 }
459
getServiceUnitName()460 std::string ServiceConfig::getServiceUnitName()
461 {
462 return instantiatedUnitName + ".service";
463 }
464
isMaskedOut()465 bool ServiceConfig::isMaskedOut()
466 {
467 // return true if state is masked & no request to update the maskedState
468 return (
469 stateValue == "masked" &&
470 !(updatedFlag & (1 << static_cast<uint8_t>(UpdatedProp::maskedState))));
471 }
472
stopAndApplyUnitConfig(boost::asio::yield_context yield)473 void ServiceConfig::stopAndApplyUnitConfig(boost::asio::yield_context yield)
474 {
475 if (!updatedFlag || isMaskedOut())
476 {
477 // No updates / masked - Just return.
478 return;
479 }
480 lg2::info("Applying new settings: {OBJPATH}", "OBJPATH", objPath);
481 if (subStateValue == subStateRunning || subStateValue == subStateListening)
482 {
483 if (!socketObjectPath.empty())
484 {
485 systemdUnitAction(conn, yield, getSocketUnitName(), sysdStopUnit);
486 }
487 if (!isSocketActivatedService)
488 {
489 systemdUnitAction(conn, yield, getServiceUnitName(), sysdStopUnit);
490 }
491 else
492 {
493 // For socket-activated service, each connection will spawn a
494 // service instance from template. Need to find all spawned service
495 // `<unitName>@<attribute>.service` and stop them through the
496 // systemdUnitAction method
497 boost::system::error_code ec;
498 auto listUnits =
499 conn->yield_method_call<std::vector<ListUnitsType>>(
500 yield, ec, sysdService, sysdObjPath, sysdMgrIntf,
501 "ListUnits");
502
503 checkAndThrowInternalFailure(
504 ec, "yield_method_call error: ListUnits failed");
505
506 for (const auto& unit : listUnits)
507 {
508 const auto& service =
509 std::get<static_cast<int>(ListUnitElements::name)>(unit);
510 const auto& status =
511 std::get<static_cast<int>(ListUnitElements::subState)>(
512 unit);
513 if (service.find(baseUnitName + "@") != std::string::npos &&
514 service.find(".service") != std::string::npos &&
515 status == subStateRunning)
516 {
517 systemdUnitAction(conn, yield, service, sysdStopUnit);
518 }
519 }
520 }
521 }
522
523 if (updatedFlag & (1 << static_cast<uint8_t>(UpdatedProp::port)))
524 {
525 createSocketOverrideConf();
526 // Create override config file and write data.
527 std::string ovrCfgFile{overrideConfDir + "/" + overrideConfFileName};
528 std::string tmpFile{ovrCfgFile + "_tmp"};
529 std::ofstream cfgFile(tmpFile, std::ios::out);
530 if (!cfgFile.good())
531 {
532 lg2::error("Failed to open the {TMPFILE} file.", "TMPFILE",
533 tmpFile);
534 phosphor::logging::elog<sdbusplus::xyz::openbmc_project::Common::
535 Error::InternalFailure>();
536 }
537
538 // Write the socket header
539 cfgFile << "[Socket]\n";
540 // Listen
541 cfgFile << "Listen" << protocol << "="
542 << "\n";
543 cfgFile << "Listen" << protocol << "=" << portNum << "\n";
544 cfgFile.close();
545
546 if (std::rename(tmpFile.c_str(), ovrCfgFile.c_str()) != 0)
547 {
548 lg2::error("Failed to rename {TMPFILE} file as {OVERCFGFILE} file.",
549 "TMPFILE", tmpFile, "OVERCFGFILE", ovrCfgFile);
550 std::remove(tmpFile.c_str());
551 phosphor::logging::elog<sdbusplus::xyz::openbmc_project::Common::
552 Error::InternalFailure>();
553 }
554 }
555
556 if (updatedFlag & ((1 << static_cast<uint8_t>(UpdatedProp::maskedState)) |
557 (1 << static_cast<uint8_t>(UpdatedProp::enabledState))))
558 {
559 std::vector<std::string> unitFiles;
560 if (socketObjectPath.empty())
561 {
562 unitFiles = {getServiceUnitName()};
563 }
564 else if (serviceObjectPath.empty())
565 {
566 unitFiles = {getSocketUnitName()};
567 }
568 else
569 {
570 unitFiles = {getSocketUnitName(), getServiceUnitName()};
571 }
572 systemdUnitFilesStateChange(conn, yield, unitFiles, stateValue,
573 unitMaskedState, unitEnabledState);
574 }
575 return;
576 }
restartUnitConfig(boost::asio::yield_context yield)577 void ServiceConfig::restartUnitConfig(boost::asio::yield_context yield)
578 {
579 if (!updatedFlag || isMaskedOut())
580 {
581 // No updates. Just return.
582 return;
583 }
584
585 if (unitRunningState)
586 {
587 if (!socketObjectPath.empty())
588 {
589 systemdUnitAction(conn, yield, getSocketUnitName(),
590 sysdRestartUnit);
591 }
592 if (!serviceObjectPath.empty())
593 {
594 systemdUnitAction(conn, yield, getServiceUnitName(),
595 sysdRestartUnit);
596 }
597 }
598
599 // Reset the flag
600 updatedFlag = 0;
601
602 lg2::info("Applied new settings: {OBJPATH} {UNIT_RUNNING_STATE}", "OBJPATH",
603 objPath, "UNIT_RUNNING_STATE", unitRunningState);
604
605 queryAndUpdateProperties();
606 return;
607 }
608
startServiceRestartTimer()609 void ServiceConfig::startServiceRestartTimer()
610 {
611 timer->expires_after(std::chrono::seconds(restartTimeout));
612 timer->async_wait([this](const boost::system::error_code& ec) {
613 if (ec == boost::asio::error::operation_aborted)
614 {
615 // Timer reset.
616 return;
617 }
618 else if (ec)
619 {
620 lg2::error("async wait error: {EC}", "EC", ec.value());
621 return;
622 }
623 updateInProgress = true;
624 boost::asio::spawn(
625 conn->get_io_context(),
626 [this](boost::asio::yield_context yield) {
627 // Stop and apply configuration for all objects
628 for (auto& srvMgrObj : srvMgrObjects)
629 {
630 auto& srvObj = srvMgrObj.second;
631 if (srvObj->updatedFlag)
632 {
633 srvObj->stopAndApplyUnitConfig(yield);
634 }
635 }
636 // Do system reload
637 systemdDaemonReload(conn, yield);
638 // restart unit config.
639 for (auto& srvMgrObj : srvMgrObjects)
640 {
641 auto& srvObj = srvMgrObj.second;
642 if (srvObj->updatedFlag)
643 {
644 srvObj->restartUnitConfig(yield);
645 }
646 }
647 updateInProgress = false;
648 },
649 boost::asio::detached);
650 });
651 }
652
registerProperties()653 void ServiceConfig::registerProperties()
654 {
655 srvCfgIface = server.add_interface(objPath, serviceConfigIntfName);
656
657 if (!socketObjectPath.empty())
658 {
659 sockAttrIface = server.add_interface(objPath, sockAttrIntfName);
660 sockAttrIface->register_property(
661 sockAttrPropPort, portNum,
662 [this](const uint16_t& req, uint16_t& res) {
663 if (!internalSet)
664 {
665 if (req == res)
666 {
667 return 1;
668 }
669 if (updateInProgress)
670 {
671 return 0;
672 }
673 portNum = req;
674 updatedFlag |=
675 (1 << static_cast<uint8_t>(UpdatedProp::port));
676 startServiceRestartTimer();
677 }
678 res = req;
679 return 1;
680 });
681 }
682
683 srvCfgIface->register_property(
684 srvCfgPropMasked, unitMaskedState, [this](const bool& req, bool& res) {
685 if (!internalSet)
686 {
687 #ifdef USB_CODE_UPDATE
688 if (baseUnitName == usbCodeUpdateUnitName)
689 {
690 unitMaskedState = req;
691 unitEnabledState = !unitMaskedState;
692 unitRunningState = !unitMaskedState;
693 internalSet = true;
694 srvCfgIface->set_property(srvCfgPropEnabled,
695 unitEnabledState);
696 srvCfgIface->set_property(srvCfgPropRunning,
697 unitRunningState);
698 srvCfgIface->set_property(srvCfgPropMasked,
699 unitMaskedState);
700 internalSet = false;
701 setUSBCodeUpdateState(unitEnabledState);
702 saveUSBCodeUpdateStateToFile(unitMaskedState,
703 unitEnabledState);
704 return 1;
705 }
706 #endif
707 if (req == res)
708 {
709 return 1;
710 }
711 if (updateInProgress)
712 {
713 return 0;
714 }
715 unitMaskedState = req;
716 unitEnabledState = !unitMaskedState;
717 unitRunningState = !unitMaskedState;
718 updatedFlag |=
719 (1 << static_cast<uint8_t>(UpdatedProp::maskedState)) |
720 (1 << static_cast<uint8_t>(UpdatedProp::enabledState)) |
721 (1 << static_cast<uint8_t>(UpdatedProp::runningState));
722 internalSet = true;
723 srvCfgIface->set_property(srvCfgPropEnabled, unitEnabledState);
724 srvCfgIface->set_property(srvCfgPropRunning, unitRunningState);
725 internalSet = false;
726 startServiceRestartTimer();
727 }
728 res = req;
729 return 1;
730 });
731
732 srvCfgIface->register_property(
733 srvCfgPropEnabled, unitEnabledState,
734 [this](const bool& req, bool& res) {
735 if (!internalSet)
736 {
737 #ifdef USB_CODE_UPDATE
738 if (baseUnitName == usbCodeUpdateUnitName)
739 {
740 if (unitMaskedState)
741 { // block updating if masked
742 lg2::error("Invalid value specified");
743 return -EINVAL;
744 }
745 unitEnabledState = req;
746 unitRunningState = req;
747 internalSet = true;
748 srvCfgIface->set_property(srvCfgPropEnabled,
749 unitEnabledState);
750 srvCfgIface->set_property(srvCfgPropRunning,
751 unitRunningState);
752 internalSet = false;
753 setUSBCodeUpdateState(unitEnabledState);
754 saveUSBCodeUpdateStateToFile(unitMaskedState,
755 unitEnabledState);
756 res = req;
757 return 1;
758 }
759 #endif
760 if (req == res)
761 {
762 return 1;
763 }
764 if (updateInProgress)
765 {
766 return 0;
767 }
768 if (unitMaskedState)
769 { // block updating if masked
770 lg2::error("Invalid value specified");
771 return -EINVAL;
772 }
773 unitEnabledState = req;
774 updatedFlag |=
775 (1 << static_cast<uint8_t>(UpdatedProp::enabledState));
776 startServiceRestartTimer();
777 }
778 res = req;
779 return 1;
780 });
781
782 srvCfgIface->register_property(
783 srvCfgPropRunning, unitRunningState,
784 [this](const bool& req, bool& res) {
785 if (!internalSet)
786 {
787 #ifdef USB_CODE_UPDATE
788 if (baseUnitName == usbCodeUpdateUnitName)
789 {
790 if (unitMaskedState)
791 { // block updating if masked
792 lg2::error("Invalid value specified");
793 return -EINVAL;
794 }
795 unitEnabledState = req;
796 unitRunningState = req;
797 internalSet = true;
798 srvCfgIface->set_property(srvCfgPropEnabled,
799 unitEnabledState);
800 srvCfgIface->set_property(srvCfgPropRunning,
801 unitRunningState);
802 internalSet = false;
803 setUSBCodeUpdateState(unitEnabledState);
804 saveUSBCodeUpdateStateToFile(unitMaskedState,
805 unitEnabledState);
806 res = req;
807 return 1;
808 }
809 #endif
810 if (req == res)
811 {
812 return 1;
813 }
814 if (updateInProgress)
815 {
816 return 0;
817 }
818 if (unitMaskedState)
819 { // block updating if masked
820 lg2::error("Invalid value specified");
821 return -EINVAL;
822 }
823 unitRunningState = req;
824 updatedFlag |=
825 (1 << static_cast<uint8_t>(UpdatedProp::runningState));
826 startServiceRestartTimer();
827 }
828 res = req;
829 return 1;
830 });
831
832 srvCfgIface->initialize();
833 if (!socketObjectPath.empty())
834 {
835 sockAttrIface->initialize();
836 }
837 return;
838 }
839
840 } // namespace service
841 } // namespace phosphor
842