xref: /openbmc/service-config-manager/src/srvcfg_manager.cpp (revision 735c6147de27b60b906c1d1d93c7d7e464840ebb)
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