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