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(bool isStartup=false)232 void ServiceConfig::queryAndUpdateProperties(bool isStartup = false)
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,
243          isStartup](boost::system::error_code ec,
244                     const boost::container::flat_map<std::string, VariantType>&
245                         propertyMap) {
246             if (ec)
247             {
248                 lg2::error(
249                     "async_method_call error: Failed to service unit properties: {EC}",
250                     "EC", ec.value());
251                 return;
252             }
253             try
254             {
255                 updateServiceProperties(propertyMap);
256                 if (!socketObjectPath.empty())
257                 {
258                     conn->async_method_call(
259                         [this](boost::system::error_code ec,
260                                const boost::container::flat_map<
261                                    std::string, VariantType>& propertyMap) {
262                             if (ec)
263                             {
264                                 lg2::error(
265                                     "async_method_call error: Failed to get all property: {EC}",
266                                     "EC", ec.value());
267                                 return;
268                             }
269                             try
270                             {
271                                 updateSocketProperties(propertyMap);
272                                 if (!srvCfgIface)
273                                 {
274                                     registerProperties();
275                                 }
276                             }
277                             catch (const std::exception& e)
278                             {
279                                 lg2::error(
280                                     "Exception in getting socket properties: {ERROR}",
281                                     "ERROR", e);
282                                 return;
283                             }
284                         },
285                         sysdService, socketObjectPath, dBusPropIntf,
286                         dBusGetAllMethod, sysdSocketIntf);
287                 }
288                 else if (!srvCfgIface)
289                 {
290                     registerProperties();
291                 }
292                 if (isStartup)
293                 {
294                     // On startup, load our persistent settings and compare to
295                     // what was read from systemd. If they are different, use
296                     // the persistent settings
297                     loadStateFile();
298                 }
299                 else
300                 {
301                     // This is just an update once we're already running so
302                     // write the values out to our persistent settings
303                     writeStateFile();
304                 }
305             }
306             catch (const std::exception& e)
307             {
308                 lg2::error("Exception in getting socket properties: {ERROR}",
309                            "ERROR", e);
310                 return;
311             }
312         },
313         sysdService, objectPath, dBusPropIntf, dBusGetAllMethod, sysdUnitIntf);
314     return;
315 }
316 
createSocketOverrideConf()317 void ServiceConfig::createSocketOverrideConf()
318 {
319     if (!socketObjectPath.empty())
320     {
321         std::string socketUnitName(instantiatedUnitName + ".socket");
322         /// Check override socket directory exist, if not create it.
323         std::filesystem::path ovrUnitFileDir(systemdOverrideUnitBasePath);
324         ovrUnitFileDir += socketUnitName;
325         ovrUnitFileDir += ".d";
326         if (!std::filesystem::exists(ovrUnitFileDir))
327         {
328             if (!std::filesystem::create_directories(ovrUnitFileDir))
329             {
330                 lg2::error("Unable to create the {DIR} directory.", "DIR",
331                            ovrUnitFileDir);
332                 phosphor::logging::elog<sdbusplus::xyz::openbmc_project::
333                                             Common::Error::InternalFailure>();
334             }
335         }
336         overrideConfDir = std::string(ovrUnitFileDir);
337     }
338 }
339 
writeStateFile()340 void ServiceConfig::writeStateFile()
341 {
342 #ifdef PERSIST_SETTINGS
343     lg2::debug("Writing Persistent State File Information to {STATE_FILE}",
344                "STATE_FILE", stateFile);
345     nlohmann::json stateMap;
346     stateMap[persistDataFileVersionStr] = persistDataFileVersion;
347     stateMap[srvCfgPropMasked] = unitMaskedState;
348     stateMap[srvCfgPropEnabled] = unitEnabledState;
349     stateMap[srvCfgPropRunning] = unitRunningState;
350 
351     std::ofstream file(stateFile);
352     file << stateMap;
353     file.close();
354 #endif
355 }
356 
loadStateFile()357 void ServiceConfig::loadStateFile()
358 {
359 #ifdef PERSIST_SETTINGS
360     lg2::debug("Loading Persistent State File Information from {STATE_FILE}",
361                "STATE_FILE", stateFile);
362     if (std::filesystem::exists(stateFile))
363     {
364         std::ifstream file(stateFile);
365         if (!file.good())
366         {
367             lg2::error("Error reading {FILEPATH}; delete it and continue",
368                        "FILEPATH", stateFile);
369             std::filesystem::remove(stateFile);
370             // rewrite file with what was ready from systemd
371             writeStateFile();
372             return;
373         }
374 
375         nlohmann::json stateMap =
376             nlohmann::json::parse(file, nullptr, false, true);
377         if (stateMap.is_discarded())
378         {
379             lg2::error("Error loading {FILEPATH}; delete it and continue",
380                        "FILEPATH", stateFile);
381             std::filesystem::remove(stateFile);
382             // rewrite file with what was ready from systemd
383             writeStateFile();
384             return;
385         }
386         else if (stateMap[persistDataFileVersionStr] != persistDataFileVersion)
387         {
388             lg2::error(
389                 "Error version:{VERSION} read from {FILEPATH} does not match expected {VERSION_EXP}; delete it and continue",
390                 "VERSION", stateMap[persistDataFileVersionStr], "FILEPATH",
391                 stateFile, "VERSION_EXP", persistDataFileVersion);
392             std::filesystem::remove(stateFile);
393             // rewrite file with what was ready from systemd
394             writeStateFile();
395             return;
396         }
397 
398         // If there are any differences, the persistent config file wins so
399         // update the dbus properties and trigger a reload to apply the changes
400         if (stateMap[srvCfgPropMasked] != unitMaskedState)
401         {
402             lg2::info(
403                 "Masked property for {FILEPATH} not equal. Setting to {SETTING}",
404                 "FILEPATH", stateFile, "SETTING", stateMap[srvCfgPropMasked]);
405             unitMaskedState = stateMap[srvCfgPropMasked];
406             updatedFlag |=
407                 (1 << static_cast<uint8_t>(UpdatedProp::maskedState));
408             startServiceRestartTimer();
409         }
410         if (stateMap[srvCfgPropEnabled] != unitEnabledState)
411         {
412             lg2::info(
413                 "Enabled property for {FILEPATH} not equal. Setting to {SETTING}",
414                 "FILEPATH", stateFile, "SETTING", stateMap[srvCfgPropEnabled]);
415             unitEnabledState = stateMap[srvCfgPropEnabled];
416             updatedFlag |=
417                 (1 << static_cast<uint8_t>(UpdatedProp::enabledState));
418             startServiceRestartTimer();
419         }
420         if (stateMap[srvCfgPropRunning] != unitRunningState)
421         {
422             lg2::info(
423                 "Running property for {FILEPATH} not equal. Setting to {SETTING}",
424                 "FILEPATH", stateFile, "SETTING", stateMap[srvCfgPropRunning]);
425             unitRunningState = stateMap[srvCfgPropRunning];
426             updatedFlag |=
427                 (1 << static_cast<uint8_t>(UpdatedProp::runningState));
428             startServiceRestartTimer();
429         }
430     }
431     else
432     {
433         // Just write out what we got from systemd if no existing config file
434         writeStateFile();
435     }
436 #endif
437 }
438 
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_)439 ServiceConfig::ServiceConfig(
440     sdbusplus::asio::object_server& srv_,
441     std::shared_ptr<sdbusplus::asio::connection>& conn_,
442     const std::string& objPath_, const std::string& baseUnitName_,
443     const std::string& instanceName_, const std::string& serviceObjPath_,
444     const std::string& socketObjPath_) :
445     conn(conn_), server(srv_), objPath(objPath_), baseUnitName(baseUnitName_),
446     instanceName(instanceName_), serviceObjectPath(serviceObjPath_),
447     socketObjectPath(socketObjPath_)
448 {
449     isSocketActivatedService = serviceObjectPath.empty();
450     instantiatedUnitName = baseUnitName + addInstanceName(instanceName, "@");
451     updatedFlag = 0;
452     stateFile = srvDataBaseDir + instantiatedUnitName;
453     queryAndUpdateProperties(true);
454     return;
455 }
456 
getSocketUnitName()457 std::string ServiceConfig::getSocketUnitName()
458 {
459     return instantiatedUnitName + ".socket";
460 }
461 
getServiceUnitName()462 std::string ServiceConfig::getServiceUnitName()
463 {
464     return instantiatedUnitName + ".service";
465 }
466 
isMaskedOut()467 bool ServiceConfig::isMaskedOut()
468 {
469     // return true  if state is masked & no request to update the maskedState
470     return (
471         stateValue == "masked" &&
472         !(updatedFlag & (1 << static_cast<uint8_t>(UpdatedProp::maskedState))));
473 }
474 
stopAndApplyUnitConfig(boost::asio::yield_context yield)475 void ServiceConfig::stopAndApplyUnitConfig(boost::asio::yield_context yield)
476 {
477     if (!updatedFlag || isMaskedOut())
478     {
479         // No updates / masked - Just return.
480         return;
481     }
482     lg2::info("Applying new settings: {OBJPATH}", "OBJPATH", objPath);
483     if (subStateValue == subStateRunning || subStateValue == subStateListening)
484     {
485         if (!socketObjectPath.empty())
486         {
487             systemdUnitAction(conn, yield, getSocketUnitName(), sysdStopUnit);
488         }
489         if (!isSocketActivatedService)
490         {
491             systemdUnitAction(conn, yield, getServiceUnitName(), sysdStopUnit);
492         }
493         else
494         {
495             // For socket-activated service, each connection will spawn a
496             // service instance from template. Need to find all spawned service
497             // `<unitName>@<attribute>.service` and stop them through the
498             // systemdUnitAction method
499             boost::system::error_code ec;
500             auto listUnits =
501                 conn->yield_method_call<std::vector<ListUnitsType>>(
502                     yield, ec, sysdService, sysdObjPath, sysdMgrIntf,
503                     "ListUnits");
504 
505             checkAndThrowInternalFailure(
506                 ec, "yield_method_call error: ListUnits failed");
507 
508             for (const auto& unit : listUnits)
509             {
510                 const auto& service =
511                     std::get<static_cast<int>(ListUnitElements::name)>(unit);
512                 const auto& status =
513                     std::get<static_cast<int>(ListUnitElements::subState)>(
514                         unit);
515                 if (service.find(baseUnitName + "@") != std::string::npos &&
516                     service.find(".service") != std::string::npos &&
517                     status == subStateRunning)
518                 {
519                     systemdUnitAction(conn, yield, service, sysdStopUnit);
520                 }
521             }
522         }
523     }
524 
525     if (updatedFlag & (1 << static_cast<uint8_t>(UpdatedProp::port)))
526     {
527         createSocketOverrideConf();
528         // Create override config file and write data.
529         std::string ovrCfgFile{overrideConfDir + "/" + overrideConfFileName};
530         std::string tmpFile{ovrCfgFile + "_tmp"};
531         std::ofstream cfgFile(tmpFile, std::ios::out);
532         if (!cfgFile.good())
533         {
534             lg2::error("Failed to open the {TMPFILE} file.", "TMPFILE",
535                        tmpFile);
536             phosphor::logging::elog<sdbusplus::xyz::openbmc_project::Common::
537                                         Error::InternalFailure>();
538         }
539 
540         // Write the socket header
541         cfgFile << "[Socket]\n";
542         // Listen
543         cfgFile << "Listen" << protocol << "="
544                 << "\n";
545         cfgFile << "Listen" << protocol << "=" << portNum << "\n";
546         cfgFile.close();
547 
548         if (std::rename(tmpFile.c_str(), ovrCfgFile.c_str()) != 0)
549         {
550             lg2::error("Failed to rename {TMPFILE} file as {OVERCFGFILE} file.",
551                        "TMPFILE", tmpFile, "OVERCFGFILE", ovrCfgFile);
552             std::remove(tmpFile.c_str());
553             phosphor::logging::elog<sdbusplus::xyz::openbmc_project::Common::
554                                         Error::InternalFailure>();
555         }
556     }
557 
558     if (updatedFlag & ((1 << static_cast<uint8_t>(UpdatedProp::maskedState)) |
559                        (1 << static_cast<uint8_t>(UpdatedProp::enabledState))))
560     {
561         std::vector<std::string> unitFiles;
562         if (socketObjectPath.empty())
563         {
564             unitFiles = {getServiceUnitName()};
565         }
566         else if (serviceObjectPath.empty())
567         {
568             unitFiles = {getSocketUnitName()};
569         }
570         else
571         {
572             unitFiles = {getSocketUnitName(), getServiceUnitName()};
573         }
574         systemdUnitFilesStateChange(conn, yield, unitFiles, stateValue,
575                                     unitMaskedState, unitEnabledState);
576     }
577     return;
578 }
restartUnitConfig(boost::asio::yield_context yield)579 void ServiceConfig::restartUnitConfig(boost::asio::yield_context yield)
580 {
581     if (!updatedFlag || isMaskedOut())
582     {
583         // No updates. Just return.
584         return;
585     }
586 
587     if (unitRunningState)
588     {
589         if (!socketObjectPath.empty())
590         {
591             systemdUnitAction(conn, yield, getSocketUnitName(),
592                               sysdRestartUnit);
593         }
594         if (!serviceObjectPath.empty())
595         {
596             systemdUnitAction(conn, yield, getServiceUnitName(),
597                               sysdRestartUnit);
598         }
599     }
600 
601     // Reset the flag
602     updatedFlag = 0;
603 
604     lg2::info("Applied new settings: {OBJPATH} {UNIT_RUNNING_STATE}", "OBJPATH",
605               objPath, "UNIT_RUNNING_STATE", unitRunningState);
606 
607     queryAndUpdateProperties();
608     return;
609 }
610 
startServiceRestartTimer()611 void ServiceConfig::startServiceRestartTimer()
612 {
613     timer->expires_after(std::chrono::seconds(restartTimeout));
614     timer->async_wait([this](const boost::system::error_code& ec) {
615         if (ec == boost::asio::error::operation_aborted)
616         {
617             // Timer reset.
618             return;
619         }
620         else if (ec)
621         {
622             lg2::error("async wait error: {EC}", "EC", ec.value());
623             return;
624         }
625         updateInProgress = true;
626         boost::asio::spawn(
627             conn->get_io_context(),
628             [this](boost::asio::yield_context yield) {
629                 // Stop and apply configuration for all objects
630                 for (auto& srvMgrObj : srvMgrObjects)
631                 {
632                     auto& srvObj = srvMgrObj.second;
633                     if (srvObj->updatedFlag)
634                     {
635                         srvObj->stopAndApplyUnitConfig(yield);
636                     }
637                 }
638                 // Do system reload
639                 systemdDaemonReload(conn, yield);
640                 // restart unit config.
641                 for (auto& srvMgrObj : srvMgrObjects)
642                 {
643                     auto& srvObj = srvMgrObj.second;
644                     if (srvObj->updatedFlag)
645                     {
646                         srvObj->restartUnitConfig(yield);
647                     }
648                 }
649                 updateInProgress = false;
650             },
651             boost::asio::detached);
652     });
653 }
654 
registerProperties()655 void ServiceConfig::registerProperties()
656 {
657     srvCfgIface = server.add_interface(objPath, serviceConfigIntfName);
658 
659     if (!socketObjectPath.empty())
660     {
661         sockAttrIface = server.add_interface(objPath, sockAttrIntfName);
662         sockAttrIface->register_property(
663             sockAttrPropPort, portNum,
664             [this](const uint16_t& req, uint16_t& res) {
665                 if (!internalSet)
666                 {
667                     if (req == res)
668                     {
669                         return 1;
670                     }
671                     if (updateInProgress)
672                     {
673                         return 0;
674                     }
675                     portNum = req;
676                     updatedFlag |=
677                         (1 << static_cast<uint8_t>(UpdatedProp::port));
678                     startServiceRestartTimer();
679                 }
680                 res = req;
681                 return 1;
682             });
683     }
684 
685     srvCfgIface->register_property(
686         srvCfgPropMasked, unitMaskedState, [this](const bool& req, bool& res) {
687             if (!internalSet)
688             {
689 #ifdef USB_CODE_UPDATE
690                 if (baseUnitName == usbCodeUpdateUnitName)
691                 {
692                     unitMaskedState = req;
693                     unitEnabledState = !unitMaskedState;
694                     unitRunningState = !unitMaskedState;
695                     internalSet = true;
696                     srvCfgIface->set_property(srvCfgPropEnabled,
697                                               unitEnabledState);
698                     srvCfgIface->set_property(srvCfgPropRunning,
699                                               unitRunningState);
700                     srvCfgIface->set_property(srvCfgPropMasked,
701                                               unitMaskedState);
702                     internalSet = false;
703                     setUSBCodeUpdateState(unitEnabledState);
704                     saveUSBCodeUpdateStateToFile(unitMaskedState,
705                                                  unitEnabledState);
706                     return 1;
707                 }
708 #endif
709                 if (req == res)
710                 {
711                     return 1;
712                 }
713                 if (updateInProgress)
714                 {
715                     return 0;
716                 }
717                 unitMaskedState = req;
718                 unitEnabledState = !unitMaskedState;
719                 unitRunningState = !unitMaskedState;
720                 updatedFlag |=
721                     (1 << static_cast<uint8_t>(UpdatedProp::maskedState)) |
722                     (1 << static_cast<uint8_t>(UpdatedProp::enabledState)) |
723                     (1 << static_cast<uint8_t>(UpdatedProp::runningState));
724                 internalSet = true;
725                 srvCfgIface->set_property(srvCfgPropEnabled, unitEnabledState);
726                 srvCfgIface->set_property(srvCfgPropRunning, unitRunningState);
727                 internalSet = false;
728                 startServiceRestartTimer();
729             }
730             res = req;
731             return 1;
732         });
733 
734     srvCfgIface->register_property(
735         srvCfgPropEnabled, unitEnabledState,
736         [this](const bool& req, bool& res) {
737             if (!internalSet)
738             {
739 #ifdef USB_CODE_UPDATE
740                 if (baseUnitName == usbCodeUpdateUnitName)
741                 {
742                     if (unitMaskedState)
743                     { // block updating if masked
744                         lg2::error("Invalid value specified");
745                         return -EINVAL;
746                     }
747                     unitEnabledState = req;
748                     unitRunningState = req;
749                     internalSet = true;
750                     srvCfgIface->set_property(srvCfgPropEnabled,
751                                               unitEnabledState);
752                     srvCfgIface->set_property(srvCfgPropRunning,
753                                               unitRunningState);
754                     internalSet = false;
755                     setUSBCodeUpdateState(unitEnabledState);
756                     saveUSBCodeUpdateStateToFile(unitMaskedState,
757                                                  unitEnabledState);
758                     res = req;
759                     return 1;
760                 }
761 #endif
762                 if (req == res)
763                 {
764                     return 1;
765                 }
766                 if (updateInProgress)
767                 {
768                     return 0;
769                 }
770                 if (unitMaskedState)
771                 { // block updating if masked
772                     lg2::error("Invalid value specified");
773                     return -EINVAL;
774                 }
775                 unitEnabledState = req;
776                 updatedFlag |=
777                     (1 << static_cast<uint8_t>(UpdatedProp::enabledState));
778                 startServiceRestartTimer();
779             }
780             res = req;
781             return 1;
782         });
783 
784     srvCfgIface->register_property(
785         srvCfgPropRunning, unitRunningState,
786         [this](const bool& req, bool& res) {
787             if (!internalSet)
788             {
789 #ifdef USB_CODE_UPDATE
790                 if (baseUnitName == usbCodeUpdateUnitName)
791                 {
792                     if (unitMaskedState)
793                     { // block updating if masked
794                         lg2::error("Invalid value specified");
795                         return -EINVAL;
796                     }
797                     unitEnabledState = req;
798                     unitRunningState = req;
799                     internalSet = true;
800                     srvCfgIface->set_property(srvCfgPropEnabled,
801                                               unitEnabledState);
802                     srvCfgIface->set_property(srvCfgPropRunning,
803                                               unitRunningState);
804                     internalSet = false;
805                     setUSBCodeUpdateState(unitEnabledState);
806                     saveUSBCodeUpdateStateToFile(unitMaskedState,
807                                                  unitEnabledState);
808                     res = req;
809                     return 1;
810                 }
811 #endif
812                 if (req == res)
813                 {
814                     return 1;
815                 }
816                 if (updateInProgress)
817                 {
818                     return 0;
819                 }
820                 if (unitMaskedState)
821                 { // block updating if masked
822                     lg2::error("Invalid value specified");
823                     return -EINVAL;
824                 }
825                 unitRunningState = req;
826                 updatedFlag |=
827                     (1 << static_cast<uint8_t>(UpdatedProp::runningState));
828                 startServiceRestartTimer();
829             }
830             res = req;
831             return 1;
832         });
833 
834     srvCfgIface->initialize();
835     if (!socketObjectPath.empty())
836     {
837         sockAttrIface->initialize();
838     }
839     return;
840 }
841 
842 } // namespace service
843 } // namespace phosphor
844